/** Notifies the listener about possible region-based events */ private void notifyListener() { IBeacon newNearestBeacon = null; if (_arrOrderedIBeacons.size() > 0) newNearestBeacon = _arrOrderedIBeacons.get(0); // Case 1: enter iBeacon region from nowhere if (_previousNearestIBeacon == null && newNearestBeacon != null) { _listener.enterRegion(newNearestBeacon); _previousNearestIBeacon = newNearestBeacon; } // Case 2: keep in the same iBeacon region, update proximity else if (_previousNearestIBeacon != null && newNearestBeacon != null && _previousNearestIBeacon.equals(newNearestBeacon)) { _previousNearestIBeacon = newNearestBeacon; } // Case 3: enter a different iBeacon region (roaming) else if (_previousNearestIBeacon != null && newNearestBeacon != null && !_previousNearestIBeacon.equals(newNearestBeacon)) { _listener.exitRegion(_previousNearestIBeacon); _listener.enterRegion(newNearestBeacon); _previousNearestIBeacon = newNearestBeacon; } // Case 4: leave iBeacon region else if (_previousNearestIBeacon != null && newNearestBeacon == null) { _listener.exitRegion(_previousNearestIBeacon); _previousNearestIBeacon = null; } }
@Override public void run() { _scanning = false; _bluetoothAdapter.stopLeScan(mLeScanCallback); if (_arrOrderedIBeacons.size() == 0) _listener.searchState(SEARCH_END_EMPTY); else _listener.searchState(SEARCH_END_SUCCESS); notifyListener(); }
/** * Starts or stops the scanning process looking for iBeacons * * @param enable <code>true</code> to start scanning, <code>false</code> to stop the scanning * process */ public void scanIBeacons(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. _timeoutHandler = new Handler(); _timeoutHandler.postDelayed(timeoutTask, IBeaconProtocol.SCANNING_PERIOD); _scanning = true; _arrOrderedIBeacons.clear(); _bluetoothAdapter.startLeScan(mLeScanCallback); _listener.searchState(SEARCH_STARTED); } else { _scanning = false; _bluetoothAdapter.stopLeScan(mLeScanCallback); _listener.searchState(SEARCH_END_SUCCESS); } // Cannot obtain error status=133 this way Log.i( Utils.LOG_TAG, "The status:" + _bluetoothAdapter.getProfileConnectionState(BluetoothProfile.GATT)); }
@Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { Log.i(Utils.LOG_TAG, "BLE packet received"); IBeacon newBeacon = parseAdvertisementData(scanRecord); if (newBeacon == null) return; newBeacon.setMacAddress(device.getAddress()); // If already discovered, then just refresh the RSSI of the existing instance and return if (_arrOrderedIBeacons.contains(newBeacon)) { double newDistance = calculateDistance(newBeacon.getPowerValue(), rssi); IBeacon previousIBeaconInfo = findIfExists(newBeacon); double oldDistance = previousIBeaconInfo.getProximity(); if (newDistance < oldDistance) { Log.i(Utils.LOG_TAG, "Updating distance"); previousIBeaconInfo.setProximity(newDistance); // Sort again Collections.sort(_arrOrderedIBeacons, new IBeaconProximityComparator()); } return; } newBeacon.setEasiBeacon(false); if (device.getName() != null) { Log.e("device.getName()", String.valueOf(device.getName())); if (device.getName().startsWith(EASIBEACON_IDPREFIX)) { newBeacon.setEasiBeacon(true); String version = device.getName().substring(EASIBEACON_IDPREFIX.length()); newBeacon.setVersionModel(version); if (newBeacon.getVersion() == 1) { // Version 1 is always connectable newBeacon.setConnectable(true); } else if (newBeacon.getVersion() == 2) { newBeacon.setConnectable(getConnectable(scanRecord)); if (!newBeacon.isConnectable()) newBeacon.setEasiBeacon(false); // If not connectable we will report it as unknown } } } // Review this Log.i( Utils.LOG_TAG, device.getName() + " " + device.getAddress() + " " + newBeacon.getPowerValue() + " " + rssi + " Connectable: " + newBeacon.isConnectable()); newBeacon.setProximity(calculateDistance(newBeacon.getPowerValue(), rssi)); if (!_arrOrderedIBeacons.contains(newBeacon)) { _arrOrderedIBeacons.add(newBeacon); Collections.sort(_arrOrderedIBeacons, new IBeaconProximityComparator()); _listener.beaconFound(newBeacon); // Every time a new beacon is found, reset the timeout _timeoutHandler.removeCallbacks(timeoutTask); _timeoutHandler.postDelayed(timeoutTask, IBeaconProtocol.SCANNING_PERIOD); } }