У меня есть служба, которая ищет маяки, когда пользователь входит в любое здание в зависимости от местоположения, которое он будет возвращать действительные регионы маяка. Служба BeaconRanger
запускается и должна начать поиск маяков в этом регионе. Это должно работать как в фоновом, так и в основном состоянии приложения. Также обновляются временные интервалы в зависимости от состояния переднего плана приложения и фонового состояния.
Обновление периодов сканирования в фоновом режиме : можно найти код в updateScanPeriods ()
private static Long BACKGROUND_SCAN_PERIOD_MEDIUM = 10 * 1000l; // 10 sec
private static Long FOREGROUND_SCAN_PERIOD_MEDIUM = 1100l; // 1.1 sec
private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 10 * 60 * 1000l; // 10 min
private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 5 * 1000l; // 5 sec
Обновление периодов сканирования на переднем плане : может найти код в updateScanPeriods ()
private static Long BACKGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
private static Long FOREGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_LOW = 4 * 1000l; // 5 sec
private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_LOW = 3 * 1000l; // 3 sec
Установить фоновый режим : может найти код в открытом доступе void onEventMainThread (BeaconRangerBackgroundSetting beaconRangerBackgroundSetting)
if (beaconRangerBackgroundSetting.status) {
if (beaconManager != null && beaconManager.isBound(this))
beaconManager.setBackgroundMode(true);
} else {
if (beaconManager != null && beaconManager.isBound(this))
beaconManager.setBackgroundMode(false);
}
Я могу получить действительные регионы в фоновом состоянии и передать его в класс BeaconRanger
, но список маяков дальнего боя всегда пуст из диспетчера Altbeacon, если я не открою приложение снова. Я реализовал RegionBootstrap / BootstrapNotifier для фонового запуска, но результат тот же.
Я хотел знать, что-то не так с моей реализацией?
public class BeaconRanger extends Service implements BeaconConsumer, BootstrapNotifier {
private static final String TAG = "ArubaBeacons";
private static final int MAX_INTERVAL = 60 * 1000; // 1 min
private static final int MIN_INTERVAL = 25 * 1000; // 25 sec
private static final int MAX_RETRY_TIME = 2 * 60 * 1000;
private static final int PERMISSION_REQUEST_STORAGE = 1;
private static Long BACKGROUND_SCAN_PERIOD_MEDIUM = 10 * 1000l; // 10 sec
private static Long FOREGROUND_SCAN_PERIOD_MEDIUM = 1100l; // 1.1 sec
private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 10 * 60 * 1000l; // 10 min
private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_MEDIUM = 5 * 1000l; // 5 sec
private static Long BACKGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
private static Long FOREGROUND_SCAN_PERIOD_LOW = 1100l; // 1.1 sec
private static Long BACKGROUND_BETWEEN_SCAN_PERIOD_LOW = 4 * 1000l; // 5 sec
private static Long FOREGROUND_BETWEEN_SCAN_PERIOD_LOW = 3 * 1000l; // 3 sec
private ArrayList<Model.beacon> beaconList = new ArrayList<Model.beacon>();
private ArrayList<Region> regions = new ArrayList<>();
private ArrayList<Region> lastRangedRegions = new ArrayList<>();
private ArrayList<Region> rangedRegions = new ArrayList<>();
private BeaconManager beaconManager;
private BeaconApplication mApp;
private long mLastRangeTime = 0;
private long mLastPostedTime = 0;
private long mLastRetryTime = 0;
private int retryCount = 0;
private EventBus mBus = EventBus.getDefault();
private ArrayList<String> regionIds = new ArrayList<>();
private ArrayList<Model.beacon> mLastRangedBeacons = new ArrayList<>();
private ArrayList<Model.beacon> mLastUpdatedBeacons = new ArrayList<>();
private RegionBootstrap regionBootstrap;
private int mLastBeaconSetting = -1;
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
try {
mApp = BeaconApplication.mInstance;
mApp.mBeaconRanger = this;
mBus.registerSticky(this);
new BackgroundPowerSaver(this);
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
// set the duration of the scan
updateScanPeriods();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
setForeground();
}
beaconManager.bind(this);
BeaconManager.setDebug(false);
} catch (Exception e) {
Timber.e("Exception in onCreate: " + e.getMessage());
}
}
@RequiresApi(api = Build.VERSION_CODES.O)
private void setForeground() {
try {
String NOTIFICATION_CHANNEL_ID = "location_service_notifications";
String channelName = "Location Service Notifications";
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
notificationChannel.setLightColor(Color.BLUE);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(notificationChannel);
Notification.Builder builder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID);
builder.setSmallIcon(R.drawable.ic_location);
builder.setContentTitle(getString(R.string.arcangel_location_beacon_notification_title));
builder.setContentText(getString(R.string.arcangel_location_beacon_notification_text));
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName())
.putExtra(Settings.EXTRA_CHANNEL_ID, notificationChannel.getId());
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(pendingIntent);
int v = beaconManager.getForegroundServiceNotificationId();
startForeground(2, builder.build());
if (beaconManager.getForegroundServiceNotificationId() < 0) {
beaconManager.enableForegroundServiceScanning(builder.build(), 2);
beaconManager.setEnableScheduledScanJobs(false);
updateScanPeriods();
}
Timber.d("started Foreground");
} catch (Exception e) {
Timber.e("Exception in setForeground: " + e.getMessage());
}
}
private void updateScanPeriods() {
int mCurrentBeaconSetting;
Long backgroundScanPeriod;
Long foregroundScanPeriod;
Long backgroundBetweenScanPeriod;
Long foregroundBetweenScanPeriod;
if ((mApp.isAppVisible()) { // app in the foreground
mCurrentBeaconSetting = 0;
backgroundScanPeriod = BACKGROUND_SCAN_PERIOD_LOW;
foregroundScanPeriod = FOREGROUND_SCAN_PERIOD_LOW;
backgroundBetweenScanPeriod = BACKGROUND_BETWEEN_SCAN_PERIOD_LOW;
foregroundBetweenScanPeriod = FOREGROUND_BETWEEN_SCAN_PERIOD_LOW;
} else { // app in the background
mCurrentBeaconSetting = 1;
backgroundScanPeriod = BACKGROUND_SCAN_PERIOD_MEDIUM;
foregroundScanPeriod = FOREGROUND_SCAN_PERIOD_MEDIUM;
backgroundBetweenScanPeriod = BACKGROUND_BETWEEN_SCAN_PERIOD_MEDIUM;
foregroundBetweenScanPeriod = FOREGROUND_BETWEEN_SCAN_PERIOD_MEDIUM;
}
if (mLastBeaconSetting != mCurrentBeaconSetting && beaconManager != null) {
beaconManager.setBackgroundScanPeriod(backgroundScanPeriod);
beaconManager.setForegroundScanPeriod(foregroundScanPeriod);
beaconManager.setBackgroundBetweenScanPeriod(backgroundBetweenScanPeriod); // callback time between scans background
beaconManager.setForegroundBetweenScanPeriod(foregroundBetweenScanPeriod); // callback time between scans foreground
mLastBeaconSetting = mCurrentBeaconSetting;
try {
beaconManager.updateScanPeriods();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void checkRangedRegionsValidity() {
if (regionIds.size() <= 0) {
beaconList.clear();
for (Region duplicateRegion : beaconManager.getRangedRegions()) {
try {
beaconManager.stopRangingBeaconsInRegion(duplicateRegion);
beaconManager.stopMonitoringBeaconsInRegion(duplicateRegion);
regionBootstrap.removeRegion(duplicateRegion);
} catch (Exception e) {
e.printStackTrace();
}
}
mLastRangedBeacons.clear();
}
}
// called by a different service, will give a valid region based on certain parameters like inside an building or location. If no condition is satisfies gives an empty array
public void setBeaconRegionIds(ArrayList<String> regionIds) {
this.regionIds = regionIds;
checkRangedRegionsValidity();
updateScanPeriods();
try {
regions.clear();
for (String regionId : regionIds) {
regions.add(new Region(regionId.toLowerCase(), Identifier.parse(regionId.toLowerCase()), null, null));
}
if (lastRangedRegions.size() == 0 || !lastRangedRegions.equals(regions)) {
lastRangedRegions = new ArrayList<>(regions);
if (beaconManager != null && beaconManager.isBound(this))
onBeaconServiceConnect();
}
} catch (Exception e) {
Timber.e(TAG + e);
}
}
private void startRanging() {
try {
if (canRun()) {
rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
if (rangedRegions.removeAll(regions)) {
for (Region duplicateRegion : rangedRegions) {
beaconManager.stopRangingBeaconsInRegion(duplicateRegion);
beaconManager.stopMonitoringBeaconsInRegion(duplicateRegion);
}
}
rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
if (regions.size() > 0 && !rangedRegions.equals(regions)) {
regions.removeAll(rangedRegions);
regionBootstrap = new RegionBootstrap(this, regions);
for (Region newRegion : regions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// regionBootstrap = new RegionBootstrap(this, newRegion);
}
beaconManager.startRangingBeaconsInRegion(newRegion);
beaconManager.startMonitoringBeaconsInRegion(newRegion);
}
}
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void addRangerNotifier() {
if (beaconManager == null)
return;
beaconManager.addRangeNotifier(new RangeNotifier() {
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (Beacon oneBeacon : beacons) {
for (int i = 0; i < beaconList.size(); i++) {
String arubaDuplicate = beaconList.get(i).id.trim();
String aruba = (oneBeacon.getId1().toString().trim() + ":" + oneBeacon.getId2().toInt() + ":" + oneBeacon.getId3().toInt()).trim();
if (aruba.equals(arubaDuplicate)) {
beaconList.remove(i);
}
}
Timber.d(TAG + "distance: " + oneBeacon.getDistance() + " id:" + oneBeacon.getId1() + "/" + oneBeacon.getId2() + "/" + oneBeacon.getId3());
beaconList.add(new Model.beacon(oneBeacon.getId1().toString().trim(), oneBeacon.getId2().toInt(), oneBeacon.getId3().toInt(), oneBeacon.getDistance()));
retryCount = 0;
}
boolean post = beaconsDifferInOrderByNth(mLastRangedBeacons, beaconList, 4);
mLastRangedBeacons = new ArrayList<>(beaconList);
if (mLastPostedTime < (System.currentTimeMillis() - 4500) && mApp.mState != null && mApp.mState.getLastKnownBeacons() == 0 && beaconList.size() > 0 && regionIds.size() > 0) {
mLastPostedTime = System.currentTimeMillis();
mBus.post(new BeaconRanger.MessageBeaconsRanged());
}
checkRangedRegionsValidity();
}
});
}
public void onEventMainThread(BeaconRangerBackgroundSetting beaconRangerBackgroundSetting) {
try {
if (beaconRangerBackgroundSetting.status) {
if (beaconManager != null && beaconManager.isBound(this))
beaconManager.setBackgroundMode(true);
} else {
if (beaconManager != null && beaconManager.isBound(this))
beaconManager.setBackgroundMode(false);
}
updateScanPeriods();
mBus.removeStickyEvent(beaconRangerBackgroundSetting);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onBeaconServiceConnect() {
if (beaconManager != null && (beaconManager.getRangingNotifiers().size() <= 0))
addRangerNotifier();
startRanging();
}
@Override
public void didEnterRegion(Region region) {
Timber.d("didEnterRegion: " + region);
try {
rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
if (!rangedRegions.contains(region) || rangedRegions.indexOf(region) < 0)
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void didExitRegion(Region region) {
Timber.d("didExitRegion: " + region);
}
@Override
public void didDetermineStateForRegion(int i, Region region) {
Timber.d("didDetermineStateForRegion: " + region);
if (i == 1) {
try {
rangedRegions = (ArrayList<Region>) beaconManager.getRangedRegions();
if ((rangedRegions.contains(region) || rangedRegions.indexOf(region) >= 0) && mLastRangedBeacons.size() == 0) {
beaconManager.stopRangingBeaconsInRegion(region);
beaconManager.startRangingBeaconsInRegion(region);
} else if (!rangedRegions.contains(region) || rangedRegions.indexOf(region) < 0) {
beaconManager.startRangingBeaconsInRegion(region);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}