1

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.

AshBringer
  • 2,614
  • 2
  • 20
  • 42
  • Have you been able to detect Bluetooth UUID + Major + Minor numbers of Gimbal brand beacons under Android with the Radius SDK? – ardrian Dec 20 '14 at 21:08
  • Sorry, I've been out. Still. I configured the Gimbal beacons just like the following link https://gimbal.com/doc/ios_proximity_ibeacon_quickstart.html. I didn't use the Radius SDK, I think you can only detect AltBeacons with it and not iBeacons. To detect the Gimbal Beacon, you can use the sample open source here : https://developer.android.com/samples/BluetoothLeGatt/project.html – AshBringer Feb 12 '15 at 18:30
  • Thanks. Yeah in the end I realised I needed to configure the Gimbal Beacons to "iBeacon" mode. Once I did that I could use other third party libs to detect the beacons. – ardrian Feb 13 '15 at 02:33

1 Answers1

1

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();

davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • Thank you for your time sir ! I will test it and let you know ! – AshBringer Nov 13 '14 at 20:40
  • If we are not scanning in the background should we use "BluetoothCrashResolver"?as the lib says "It is rare for most users but can be problematic for those with apps scanning for Bluetooth LE devices in the background". – Raj Trivedi Jun 10 '15 at 08:15
  • The same crashes cash happen for foreground only apps, yes, they are just less frequent – davidgyoung Jun 10 '15 at 10:57
  • Suppose Bluetooth in initially off.My app starts then it asks for BL turning on.User turns on BL.BLCrashResolver says crash has happened.Reason-lastBluetoothTurningOnTime=01/01/1970;lastBluetoothOffTime=01/01/1970;I have done BLCR.start() in my scanning class just before scanning starts.Any tips on how to take care of this? – Raj Trivedi Jun 11 '15 at 06:01
  • Yes, manually toggling bluetooth gets treated just like a crash -- the crash resolver cannot tell the difference. Does it matter? The crash resolver just does a bluetooth discovery operation. It is pretty harmless. I say just ignore this situation. – davidgyoung Jun 11 '15 at 12:29
  • It matters to my app.As everyone may not remember to keep BL On before using. so I need to check for this first..Is there any way I can bypass this particular case and still use BLCrashResolver?Currently,it is crashing as soon as the app starts. – Raj Trivedi Jun 11 '15 at 13:47
  • Sorry, I'm afraid I'm not following. I'd suggest opening a new question and explaining in a little more detail the sequence. – davidgyoung Jun 11 '15 at 17:39
  • why does the manual toggling also gets treated as a crash?user may turn the bluetooth on or off anytime he wants. – Raj Trivedi Jun 12 '15 at 12:20
  • There is no way to detect a crash of the bluetooth stack on Android without having read access to the logs, which normal user apps do not have. As a result, the way a crash is detected is by listening for bluetooth off/on events, and assuming a crash happens if the off/on interval is 600ms or less. See here for details: https://github.com/RadiusNetworks/bluetooth-crash-resolver/blob/master/app/src/main/java/com/radiusnetworks/bluetooth/BluetoothCrashResolver.java#L68 – davidgyoung Jun 12 '15 at 13:10
  • ok.so what should I do if I want to use BluetoothCrashResolver?Plz refer http://stackoverflow.com/questions/30795895/bluetoothcrashresolver-detects-a-crash-on-app-launch for individual blog on this. – Raj Trivedi Jun 14 '15 at 09:27