I followed a tutorial on Bluetooth Low Energy, and I have started to add my own menus, etc.
The question I have is, why would MainActivity be static and put inside another class.
The full tutorial is available on Github: https://github.com/kaviles/BLE_Tutorials
Below is the Scanner_BTLE class that contains static MainActivity.
public class Scanner_BTLE {
private MainActivity ma;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private long scanPeriod;
private int signalStrength;
private UUID[] uuids;
// ToDO add Runtime Permissions to activate it momentarily once user asks for scanning
// ToDo this is currently done in App permitions while in dedug mode, add the software in the code so //permisiions does not have to be done on phone
// ToDo see "https://andela.com/insights/how-to-scan-for-android-bluetooth-low-energy-devices-successfully/"
// ToDO Look at "B- or add Runtime Permissions..... " on how to add it in code
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public Scanner_BTLE(Scanner_BTLE.MainActivity mainActivity, long scanPeriod, int signalStrength) {
ma = mainActivity;
mHandler = new Handler();
this.scanPeriod = scanPeriod;
this.signalStrength = signalStrength;
final BluetoothManager bluetoothManager =
(BluetoothManager) ma.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
}
public boolean isScanning() {
return mScanning;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void start() {
if (!Utils.checkBluetooth(mBluetoothAdapter)) {
Utils.requestUserBluetooth(ma);
ma.stopScan();
}
else {
scanLeDevice(true);
}
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void stop() {
scanLeDevice(false);
}
//ToDo Use the Callback to find only the sps UUID of Relay
// If you want to scan for only specific types of peripherals,
// you can instead call startLeScan(UUID[], BluetoothAdapter.LeScanCallback),
// providing an array of UUID objects that specify the GATT services your app supports.
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void scanLeDevice(final boolean enable) {
if (enable && !mScanning) {
Utils.toast(ma.getApplicationContext(), "Starting BLE scan...");
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
Utils.toast(ma.getApplicationContext(), "Stopping BLE scan...");
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
ma.stopScan();
}
}, scanPeriod);
mScanning = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mBluetoothAdapter.startLeScan(mLeScanCallback);
}
}
else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
final int new_rssi = rssi;
if (rssi > signalStrength) {
mHandler.post(new Runnable() {
#Override
public void run() {
ma.addDevice(device, new_rssi);
}
});
}
}
};
public static class MainActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {
private final static String TAG = MainActivity.class.getSimpleName();
public static final int REQUEST_ENABLE_BT = 1;
public static final int BTLE_SERVICES = 2;
private HashMap<String, BTLE_Device> mBTDevicesHashMap;
private ArrayList<BTLE_Device> mBTDevicesArrayList;
private ListAdapter_BTLE_Devices adapter;
private ListView listView;
private Button btn_Scan;
private BroadcastReceiver_BTState mBTStateUpdateReceiver;
private Scanner_BTLE mBTLeScanner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Utils.toast(getApplicationContext(), "BLE not supported");
finish();
}
mBTStateUpdateReceiver = new BroadcastReceiver_BTState(getApplicationContext());
mBTLeScanner = new Scanner_BTLE(this, 5000, -75);
mBTDevicesHashMap = new HashMap<>();
mBTDevicesArrayList = new ArrayList<>();
adapter = new ListAdapter_BTLE_Devices(this, R.layout.btle_device_list_item, mBTDevicesArrayList);
listView = new ListView(this);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
btn_Scan = (Button) findViewById(R.id.btn_scan);
((ScrollView) findViewById(R.id.scrollView)).addView(listView);
findViewById(R.id.btn_scan).setOnClickListener(this);
}
#Override
protected void onStart() {
super.onStart();
registerReceiver(mBTStateUpdateReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
}
#Override
protected void onResume() {
super.onResume();
// registerReceiver(mBTStateUpdateReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
}
#Override
protected void onPause() {
super.onPause();
// unregisterReceiver(mBTStateUpdateReceiver);
stopScan();
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(mBTStateUpdateReceiver);
stopScan();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#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) {
// Utils.toast(getApplicationContext(), "Thank you for turning on Bluetooth");
}
else if (resultCode == RESULT_CANCELED) {
Utils.toast(getApplicationContext(), "Please turn on Bluetooth");
}
}
else if (requestCode == BTLE_SERVICES) {
// Do something
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Context context = view.getContext();
// Utils.toast(context, "List Item clicked");
// do something with the text views and start the next activity.
stopScan();
String name = mBTDevicesArrayList.get(position).getName();
String address = mBTDevicesArrayList.get(position).getAddress();
Intent intent = new Intent(this, Activity_BTLE_Services.class);
intent.putExtra(Activity_BTLE_Services.EXTRA_NAME, name);
intent.putExtra(Activity_BTLE_Services.EXTRA_ADDRESS, address);
startActivityForResult(intent, BTLE_SERVICES);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_scan:
Utils.toast(getApplicationContext(), "Scan Button Pressed");
if (!mBTLeScanner.isScanning()) {
startScan();
}
else {
stopScan();
}
break;
default:
break;
}
}
public void addDevice(BluetoothDevice device, int rssi) {
String address = device.getAddress();
if (!mBTDevicesHashMap.containsKey(address)) {
BTLE_Device btleDevice = new BTLE_Device(device);
btleDevice.setRSSI(rssi);
mBTDevicesHashMap.put(address, btleDevice);
mBTDevicesArrayList.add(btleDevice);
}
else {
mBTDevicesHashMap.get(address).setRSSI(rssi);
}
adapter.notifyDataSetChanged();
}
public void startScan(){
btn_Scan.setText("Scanning...");
mBTDevicesArrayList.clear();
mBTDevicesHashMap.clear();
mBTLeScanner.start();
}
public void stopScan() {
btn_Scan.setText("Scan Again");
mBTLeScanner.stop();
}
}
}
Related
Here I have a listview to show the list of scanned ble devices. This is working fine in ListActivity, but I want to do the same scan on DialogFragment on a button click. The working code which I have used in ListActivity is not working in DialogFragment. It is not even showing the Dialogfragment itself when I click on Button to trigger the dialog. so I have added a time with handler for 1500ms. then It shows only the Dialog title but not the list of scanned device. any idea to achieve list of scanned devices in Dialogfragment
public class DeviceScanDialogFragment extends DialogFragment
{
private static final String TAG = "DeviceScan";
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
private BluetoothDevice selectedDevice;
private Logger logger = LoggerFactory.getLogger(this.getClass());
private String calledFrom;
//persist the value about where to start the application
public static boolean isVerified = false, isPinChanged = false, isFingerPrintRegistered = false;
private SharedPreferences sharedPreferences;
private ListView listview;
public DeviceScanDialogFragment() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(getActivity(), R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
getActivity().finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
// logger.info("Bluetooth adapter is null");
Toast.makeText(getActivity(), R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
getActivity().finish();
return;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.list_dialog_fragment, container);
listview = (ListView) rootview.findViewById(R.id.list);
Toast.makeText(getActivity(), "Executed", Toast.LENGTH_SHORT).show();
// getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().setTitle("Scan List Title");
return rootview;
}
#Override
public void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
// logger.info("Enabling bluetooth");
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
listview.postDelayed(new Runnable() {
#Override
public void run() {
// Initializes list view adapter.
mLeDeviceListAdapter = new LeDeviceListAdapter();
listview.setAdapter(mLeDeviceListAdapter);
scanLeDevice(true);
}
},1500);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
getActivity().finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onPause() {
super.onPause();
scanLeDevice(false);
mLeDeviceListAdapter.clear();
// save(isVerified, isPinChanged, isFingerPrintRegistered);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
if (mBluetoothAdapter != null) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
if (mBluetoothAdapter.getBondedDevices().size() == 0)
Toast.makeText(getActivity(), "No Device Found", Toast.LENGTH_SHORT).show();
if (getActivity() != null) {
if (isVisible())
dismiss();
}
}
// invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
// logger.info("Scanning without UUIDs");
mBluetoothAdapter.startLeScan(mLeScanCallback);
/*UUID[] uuids = new UUID[1];
Log.e(TAG, "Length of UUID[]= " + uuids.length);
uuids[0] = UUID.fromString(SampleGattAttributes.JACKET_UUID);
logger.info("Scanning with UUIDs");
mBluetoothAdapter.startLeScan(uuids, mLeScanCallback);*/
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
// invalidateOptionsMenu();
}
// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflater;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflater = getActivity().getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if (!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
#Override
public int getCount() {
return mLeDevices.size();
}
#Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflater.inflate(R.layout.listitem_device, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(position);
final String deviceName = device.getName();
Log.i(TAG, "name:" + deviceName + ", Address :" + device.getAddress());
if (deviceName != null && deviceName.length() > 0) {
viewHolder.deviceName.setText(deviceName);
if (deviceName.contains("Test")) {
selectedDevice = mLeDeviceListAdapter.getDevice(position);
if (selectedDevice != null) {
Intent intent;
intent = new Intent(getActivity(), NavigationDrawerActivity.class);
intent.putExtra("address", selectedDevice.getAddress());
if (mScanning) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mScanning = false;
}
startActivity(intent);
}
}
} else {
viewHolder.deviceName.setText(R.string.unknown_device);
}
viewHolder.deviceAddress.setText(device.getAddress());
return view;
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
}
On Button click I am Calling this method to trigger the Dialogfragment
public void showScanDialog() {
FragmentManager manager = getSupportFragmentManager();
DeviceScanDialogFragment dialog = new DeviceScanDialogFragment();
dialog.show(manager, "devicescan");
}
Everything is working fine when I turned off wifi, because BLE won't stable with wifi and Using BLE in Marshmallow Devices will won't show the Scanned devices which are nearby. so just I have added permissions for location access for Marshmallow supported Devices, Then it worked fine.
I am developing an App which connects to heart rate sensor and retrives the values. I am using BLE 4.0.
With the help of google developer portal, I was able to build some code, but the app is crashing.
Please help me out. And also I need to sync the data which I have not able to able properly.
Code:
public class PollingTest extends Activity{
public Button btn2;
public static String UUID = "00001101-0000-1000-8000-00805F9B34FB";
public boolean mScanning;
public Handler mHandler;
public LeDeviceListAdapter mLeDeviceListAdapter;
public BluetoothAdapter mBluetoothAdapter;
static final int REQUEST_ENABLE_BT = 1;
public static final long SCAN_PERIOD = 10000; // Stops scanning after 10 seconds.
#Override
protected void onCreate(Bundle savedInstanceStat){
super.onCreate(savedInstanceStat);
setContentView(R.layout.pollingactivity);
btn2 = (Button)findViewById(R.id.pollB);
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
//mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
btn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(getApplicationContext(), "Bluetooth Low Energy is not supported on this Device ", Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(getApplicationContext(), "Bluetooth not Supported", Toast.LENGTH_SHORT).show();
finish();
return;
}
else {
if (!mBluetoothAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
} else {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
scanLeDevice(true);
}
}
}
});
}
#Override
protected void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
//mLeDeviceListAdapter.clear();
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//String macAddress;
//macAddress = device.getAddress();
Toast.makeText(getApplicationContext(),device.getAddress(),Toast.LENGTH_LONG).show();
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
/*switch (device.getAddress().toUpperCase()){
case "8C:DE:52:64:8E:D1":
Toast.makeText(getApplicationContext(), "First",Toast.LENGTH_LONG).show();
}*/
}
});
}
};
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<>();
mInflator = PollingTest.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if(!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
#Override
public int getCount() {
return mLeDevices.size();
}
#Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
}
Here I have commented onResume & onPause methods because,if dont,the app is getting crashed.
Log
I think device in LeScan if not able to access/receive bluetooth object for some weird reason or something. Please help me out
Thank You
It's because DeviceScanActivity.this returns 'null' (that pattern is likely not correctly set up), so when you call DeviceScanActivity.this.getLayoutInflater(), you get a NullPointerException, because you're trying to call getLayoutInflater() on something that does not exist.
I already asked the question but without success.
So I have a list of bluetooth devices. I'm assuming I have only one item (one device) in this list. When I click to this item, onListItemClick() method from ListActivity is called. What I would like to do is selecting this item without the click of the user so I 'd like to simulate a click with the function performclick().
Here is my code :
public class DeviceScanActivity extends ListActivity {
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
BluetoothCrashResolver bluetoothCrashResolver;
//UUID[] uuids = { UUID.fromString("1811")};
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setTitle(R.string.title_devices);
mHandler = new Handler();
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
if (!mScanning) {
menu.findItem(R.id.menu_stop).setVisible(false);
menu.findItem(R.id.menu_scan).setVisible(true);
menu.findItem(R.id.menu_refresh).setActionView(null);
} else {
menu.findItem(R.id.menu_stop).setVisible(true);
menu.findItem(R.id.menu_scan).setVisible(false);
menu.findItem(R.id.menu_refresh).setActionView(
R.layout.actionbar_indeterminate_progress);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_scan:
mLeDeviceListAdapter.clear();
scanLeDevice(true);
break;
case R.id.menu_stop:
scanLeDevice(false);
break;
}
return true;
}
#Override
protected void onResume() {
super.onResume();
bluetoothCrashResolver = new BluetoothCrashResolver(this.getApplicationContext());
bluetoothCrashResolver.start();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
// Initializes list view adapter.
mLeDeviceListAdapter = new LeDeviceListAdapter();
setListAdapter(mLeDeviceListAdapter);
scanLeDevice(true);
if(mLeDeviceListAdapter.getCount() >0) {
getListView().performItemClick(getListView().getAdapter().getView(0, null, null), 0, 0);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
bluetoothCrashResolver.stop();
mLeDeviceListAdapter.clear();
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);
if (device == null) return;
final Intent intent = new Intent(this, DeviceControlActivity.class);
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName());
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress());
if (mScanning) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mScanning = false;
}
startActivity(intent);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflator = DeviceScanActivity.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if(!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
#Override
public int getCount() {
return mLeDevices.size();
}
#Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.listitem_device, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(i);
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0)
viewHolder.deviceName.setText(deviceName);
else{
viewHolder.deviceName.setText(R.string.unknown_device);
viewHolder.deviceAddress.setText(device.getAddress());
}
return view;
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
bluetoothCrashResolver.notifyScannedDevice(device, mLeScanCallback);
}
});
}
};
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
}
in onResume() function, I have added those lines :
if(mLeDeviceListAdapter.getCount() >0) {
getListView().performItemClick(getListView().getAdapter().getView(0, null, null), 0, 0);
}
but nothing changed. I still have to click myself to the item and I can't see where the problem comes from. And if I put off the line
mLeDeviceListAdapter.getCount() >0
the app crashes
Thank you in advance
Since you're passing null for both convertView and parent you're essentially creating a new parentless view. Clicking it won't call the ListView's onClickListener.
You should get the view directly from the ListView, not the adapter:
list.performItemClick(list.getChildAt(0), 0, list.getItemIdAtPosition(0));
Update:
Try delaying the click:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
list.performItemClick(list.getChildAt(0), 0, list.getItemIdAtPosition(0));
}
}, 2000);
I'm trying to scan gimbal beacon with an app, that works actually well. But since I use gimbal beacon, I'm struggling with bluetooth crash.
This is exactly my problem :
https://github.com/RadiusNetworks/bluetooth-crash-resolver
Now I want to use this class but I really don't know how to apply it on this code which is :
public class DeviceScanActivity extends ListActivity {
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setTitle(R.string.title_devices);
mHandler = new Handler();
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
// Initializes a Bluetooth adapter. For API level 18 and above, get a reference to
// BluetoothAdapter through BluetoothManager.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.
if (mBluetoothAdapter == null) {
Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
finish();
return;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
if (!mScanning) {
menu.findItem(R.id.menu_stop).setVisible(false);
menu.findItem(R.id.menu_scan).setVisible(true);
menu.findItem(R.id.menu_refresh).setActionView(null);
} else {
menu.findItem(R.id.menu_stop).setVisible(true);
menu.findItem(R.id.menu_scan).setVisible(false);
menu.findItem(R.id.menu_refresh).setActionView(
R.layout.actionbar_indeterminate_progress);
}
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_scan:
mLeDeviceListAdapter.clear();
scanLeDevice(true);
break;
case R.id.menu_stop:
scanLeDevice(false);
break;
}
return true;
}
#Override
protected void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
// Initializes list view adapter.
mLeDeviceListAdapter = new LeDeviceListAdapter();
setListAdapter(mLeDeviceListAdapter);
scanLeDevice(true);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
mLeDeviceListAdapter.clear();
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);
if (device == null) return;
final Intent intent = new Intent(this, DeviceControlActivity.class);
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName());
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress());
if (mScanning) {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mScanning = false;
}
startActivity(intent);
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
invalidateOptionsMenu();
}
// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflator = DeviceScanActivity.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if(!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
#Override
public int getCount() {
return mLeDevices.size();
}
#Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.listitem_device, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(i);
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0)
viewHolder.deviceName.setText(deviceName);
else
viewHolder.deviceName.setText(R.string.unknown_device);
viewHolder.deviceAddress.setText(device.getAddress());
return view;
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
available here : http://developer.android.com/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html .
So for the moment , I just copied the BluetoothCrashSolver.java in my project and i really don't know where to place the code on steps 2) 3) and 4) in this code.
Thank you in advance.
At the top of your class, declare:
BlutoothCrashResolver bluetoothCrashResolver;
In your onResume method simply add:
bluetoothCrashResolver = new BlutoothCrashResolver(this.getApplicationContext()); bluetoothCrashResolver.start();
In your onLeScan method add:
bluetoothCrashResolver.notifyScannedDevice(device, mLeScanCallback);
Then in your onPause method add:
bluetoothCrashResolver.stop();
I am referring to developer docs to scan BLE devices -
http://developer.android.com/guide/topics/connectivity/bluetooth-le.html
In my activity class LookUpActivity, I called a method findBLE() on a button click-
//This will scan BLE devices
public void findBLE()
{
Intent intent = new Intent(LookUpActivity.this, DeviceScanActivity.class);
startActivity(intent);
}
But got the following exception -
Could not find class 'com.testapp.main.DeviceScanActivity$1',
referenced from method com.testapp.main.DeviceScanActivity.<init>
com.testapp.main fatal error : com.testapp.main.DeviceScanActivity$1
java.lang.NoClassDefFoundError: com.testapp.main.DeviceScanActivity$1
at com.testapp.main.DeviceScanActivity.<init>(DeviceScanActivity.java:179)
DeviceScanActivity.java ---
/**
* Activity for scanning and displaying available Bluetooth LE devices.
*/
#SuppressLint("NewApi")
public class DeviceScanActivity extends ListActivity {
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
}
#Override
protected void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
// Initializes list view adapter.
mLeDeviceListAdapter = new LeDeviceListAdapter();
setListAdapter(mLeDeviceListAdapter);
scanLeDevice(true);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onPause() {
super.onPause();
scanLeDevice(false);
mLeDeviceListAdapter.clear();
}
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflator = DeviceScanActivity.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if(!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
#Override
public int getCount() {
return mLeDevices.size();
}
#Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.mapentries, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.entriestitle);
//viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(i);
final String deviceName = device.getName();
/* if (deviceName != null && deviceName.length() > 0)
viewHolder.deviceName.setText(deviceName);
else
viewHolder.deviceName.setText(R.string.unknown_device);*/
viewHolder.deviceAddress.setText(device.getAddress());
return view;
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() { //This is line 179 causing error...
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
static class ViewHolder {
//TextView deviceName;
TextView deviceAddress;
}
}
UPDATE:
In order to be more specific, I downloaded the exact project code for BLE from ---
http://developer.android.com/samples/BluetoothLeGatt/project.html
And again got the same exception even using the code mentioned in the project.
This time the error console--
FATAL EXCEPTION: main
java.lang.NoClassDefFoundError:
com.example.android.bluetoothlegatt
.DeviceScanActivity$1
at com.example.android.bluetoothlegatt.DeviceScanActivity.
<init> (DeviceScanActivity.java:250)
You must perform the full check to see if the device supports Bluetooth Low Energy (BLE). The device could be running Android 4.3 or later but lacks the hardware necessary for BLE. The Nexus 7 (2012) is an example of such device. Here's the code:
private boolean bleCheck() {
boolean result = false;
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager != null) {
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter != null) {
if (mBluetoothAdapter.isEnabled()) {
result = true;
}
}
}
}
return result;
}