0

I have trouble with showing my app on region entered, I followed the sample here. It works when I don't bind the BeaconManager to my Activty, but when I do, I get the logs from the Activity not from the Application and the app doesn't show up although it's not visible.

So the question is, can I use a class extends Application implements BootstrapNotifier for starting the app in background and a class extends AppCompatActivity implements BeaconConsumer to handle monitoring/ranging or do I need to handle everything in the application class because binding it in the activity fails the background launch?

(Sorry for the bad code block, I just can't handle this stackoverflow code thing correctly)

    public class BeaconActivity extends AppCompatActivity implements BeaconConsumer {

    protected final String TAG = "BeaconActivity";
    private BeaconManager beaconManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate()");
        setContentView(R.layout.activity_beacon);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

       RangedBeacon.setSampleExpirationMilliseconds(8000);
       beaconManager = BeaconManager.getInstanceForApplication(this);
       beaconManager.bind(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Unbind Beaconmanager");
        beaconManager.unbind(this);
    }

    @Override
    public void onBeaconServiceConnect() {
        beaconManager.setMonitorNotifier(new MonitorNotifier() {
            @Override
            public void didEnterRegion(final Region region) {
                Log.d(TAG, "Enter Region identifier: " + region.getId1() + ", " + region.getId2() + ", " + region.getId3());
            }

            @Override
            public void didExitRegion(final Region region) {
                Log.d(TAG, "Exit Region identifier: " + region.getId1() + ", " + region.getId2() + ", " + region.getId3());
            }

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

            }
        });

        beaconManager.setRangeNotifier(new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
                for (final Beacon beacon : beacons) {
                    final String distance = new DecimalFormat("##.######").format(beacon.getDistance());
                    Log.d(TAG, "Distance: " + distance + ". This beacon has identifiers:" + beacon.getId1() + ", " + beacon.getId2() + ", " + beacon.getId3());
                }
            }
        });

        try {
            Region region = new Region("all", null, null, null);
            beaconManager.startMonitoringBeaconsInRegion(all);
            beaconManager.startRangingBeaconsInRegion(all);
        } catch (RemoteException e) {
        }
    }
}



public class BeaconApplication extends Application implements BootstrapNotifier {

        private static final String TAG = "BeaconApplication";
        private RegionBootstrap regionBootstrap;

        @Override
        public void onCreate() {
            super.onCreate();
            Log.d(TAG, "App started up");
            BeaconManager 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"));

            Region all = new Region("all", null, null, null);
            regionBootstrap = new RegionBootstrap(this, all);
        }

        @Override
        public void didEnterRegion(Region region) {
            Log.d(TAG, "Enter region " + region.getUniqueId());
    //        regionBootstrap.disable();
            Intent intent = new Intent(this, BeaconActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            this.startActivity(intent);
        }

        @Override
        public void didExitRegion(Region region) {
            Log.d(TAG, "Exit region " + region.getUniqueId());
        }

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

Edit: I think I might just screwed up a little. Explained here the app only launches if killed (not in task switcher anymore). If it's available in task switcher it just handles the incoming events in the background, that's why I get the activity logs.

Zuop
  • 584
  • 5
  • 7
  • 21
  • Can you explain what you mean by "because binding it in the activity fails the background launch"? – davidgyoung May 11 '16 at 14:33
  • I thought if i call `beaconManager.bind(this);` in BeaconActivity the background launches from BeaconApplication dont work anymore. But I think I know why now (see edit). Can you confirm that binding the beaconmanager to the activity doesn't affect the application class at all? – Zuop May 11 '16 at 14:45
  • It should not affect the application class, no. That is how the RangingActivity works in the reference app: https://github.com/AltBeacon/android-beacon-library-reference/blob/master/app/src/main/java/org/altbeacon/beaconreference/RangingActivity.java – davidgyoung May 11 '16 at 14:56
  • And to clarify, the app should not only launch if not in the task switcher anymore. The scanning service will keep running, and entry/exit callbacks should keep coming to the Application class. I would check to see if you see your debug lines in didEnterRegion and didExitRegion. – davidgyoung May 11 '16 at 14:59

1 Answers1

0

The problem is that you can only have one monitorNotifier for your application. The RegionBootstrap class sets one internally, and uses it to get callbacks to your Application class.

The code shown above changes the monitorNotifier here:

public void onBeaconServiceConnect() {
    beaconManager.setMonitorNotifier(new MonitorNotifier() {
...

After that line executes, the RegionBootstrap won't get any more callbacks on entry/exit events, and nor will the Application class. So the problem isn't the bind() call, it's the setMonitorNotifier call.

The library does not allow multiple monitorNotifiers, so if you want to keep using the RegionBootstrap you have to refactor your code so that you get all of the entry/exit events in your Application class and somehow pass them off to your Activity.

davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • Okay, problem now is that i don't get exit region calls (in application class). Only when I kill the app in task switcher the exit region triggers. The ranging in the BeaconActivity doesnt work since I added the application class too. Is there also only one `rangingNotifier` allowed? Though the activity is visible, do i need to set the scan times faster? I really struggle to combine the first samples (monitoring/ranging in one activity) and then add the background launch example. But I guess the main problem was answered. – Zuop May 12 '16 at 09:13
  • Yes, the `BeaconManager` is a singleton so there is only one ranging notifier active at any given time. I recommend using the `BackgroundPowerSaver` in your Application class to set scan intervals automatically as you move from background to foreground and not call methods to set the background mode directly. – davidgyoung May 12 '16 at 12:59