Search code examples
androidibeacon-androidaltbeacon

iBeacon on Android to notify away within the area


I have the following code and am trying to notify 5 in 5 seconds the distance traveled within the ibeacon area.

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.multidex.MultiDex;
import android.util.Log;
import android.os.Handler;

import org.altbeacon.beacon.BeaconConsumer;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconParser;
import org.altbeacon.beacon.Identifier;
import org.altbeacon.beacon.RangeNotifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.powersave.BackgroundPowerSaver;
import org.altbeacon.beacon.startup.BootstrapNotifier;
import org.altbeacon.beacon.startup.RegionBootstrap;

import java.util.ArrayList;
import java.util.Collection;

public class MyAppApplication extends Application implements BootstrapNotifier, BeaconConsumer {


    private RegionBootstrap regionBootstrap;
    private BackgroundPowerSaver backgroundPowerSaver;
    private BeaconManager beaconManager;
    private Beacon connectedBeacon;
    private SharedPreferences prefs;

    final Handler handler = new Handler();

    private static boolean appIsForeground;
    private Runnable r;

    @Override
    public void onCreate() {
        super.onCreate();
        MultiDex.install(getBaseContext());

        prefs = getSharedPreferences(BuildConfig.SHARED_PREFS, Context.MODE_PRIVATE);

        beaconManager = BeaconManager.getInstanceForApplication(this);

        beaconManager.getBeaconParsers().clear();
        beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(ConstantsMyApp.IBEACON_LAYOUT));

        final ArrayList<Beacon> beaconArrayList = BeaconModel.selectAllBeacons(this); //get all ibeacons in the db

        beaconManager.bind(this);
        beaconManager.setMonitorNotifier(this);
        beaconManager.setForegroundScanPeriod(5285);
        beaconManager.setBackgroundBetweenScanPeriod(400);

        for (Beacon savedBeacon: beaconArrayList) {

            Region region = new Region(savedBeacon.getId() + "",
                    Identifier.parse(savedBeacon.getProximityUuid()),
                    Identifier.parse(savedBeacon.getMajor()),
                    Identifier.parse(savedBeacon.getMinor()));
            regionBootstrap = new RegionBootstrap(this, region); //work to background app

            try {

                beaconManager.startRangingBeaconsInRegion(region);

            } catch (RemoteException e) {
                Log.e("ERROR", e.toString());
            }
        }

        backgroundPowerSaver = new BackgroundPowerSaver(this);

        r = new Runnable() {
            @Override
            public void run() {
               Log.i("INFO", "iBeacon distance " + connectedBeacon.getDistance());

               handler.postDelayed(r, 5000);

            }
        };

    }

    @Override
    public void didEnterRegion(Region region) {

        if (region != null) {

            connectedBeacon = BeaconModel.selectBeacon(this, region.getId2().toString(),
                    region.getId3().toString(),
                    region.getId1().toString());

        }

        if (connectedBeacon != null) {

             Log.i("INFO", "Enter area iBeacon");

        }

    }

    @Override
    public void didExitRegion(Region region) {

        if (region != null) {

            connectedBeacon = BeaconModel.selectBeacon(this, region.getId2().toString(),
                    region.getId3().toString(),
                    region.getId1().toString());

        }

        if (connectedBeacon != null) {

            if(handler != null) {

                handler.removeCallbacks(runnable); 

            }

           Log.i("INFO", "Exit area iBeacon");

        }

    }

    @Override
    public void didDetermineStateForRegion(int state, Region region) { }

    @Override
    public void onBeaconServiceConnect() {

        Log.i("DEBUG+", "didRangeBeaconsInRegion: ");

        beaconManager.setRangeNotifier(new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<org.altbeacon.beacon.Beacon> beacons, Region region) {

                if (beacons.size() > 0) {

                    connectedBeacon = beacons.iterator().next();

                    String beaconUuid = connectedBeacon.getId1().toString();
                    String regionUuid = region.getId1().toString();

                    Log.i("DEBUG+", "beaconUuid: " + beaconUuid + " regionUuid " + regionUuid);

                    if(beaconUuid.equals(regionUuid)) {                       

                        if (connectedBeacon != null) {

                            Log.i("DEBUG+", "connectedBeacon.getId(): " + connectedBeacon.getId() +
                                    " connectedBeacon.getDistance() " + connectedBeacon.getDistance());


                            handler.postDelayed(r, 5000);                                   


                        }

                    }

                }

            }

        });

    }

    public Activity getCurrentActivity() {
        return currentActivity;
    }

    public void setCurrentActivity(Activity currentActivity) {
        this.currentActivity = currentActivity;
    }

    public Beacon getConnectedBeacon(){
        return connectedBeacon;
    }

    public static boolean isAppIsForeground() {
        return appIsForeground;
    }

    public static void appResumed(){
        appIsForeground = true;
    }

    public static void appPaused(){
        appIsForeground = false;
    }

}

I am using the library for this function on Android.

This notification must take place even with the app in the background.


Solution

  • Move the calls to beaconManager.startRangingBeaconsInRegion(region); to happen after you get the onBeaconServiceConnected callback. I suspect these calls are failing because the service is not bound yet, and the error messages are getting put in the logs.