2
votes

I'm working on a simple beacon proximity app using AltBeacon library from here https://altbeacon.github.io/android-beacon-library/samples.html

I am experimenting with the sample code provided on the above website, however, each time I run the app it only goes to didDetermineStateForRegion() method. If it detected the beacon it would go to didEnterRegion() method.

I'm not sure what I'm doing wrong and was unable to find the answer in other questions.

There is the same issue with the reference app provided on the mentioned website but Locate app (based on AltBeacon) instantly detects my beacon.

My beacon is set to 152ms transmission interval and maximum transmission power.

This is my code:

MainActivity

public class MainActivity extends AppCompatActivity implements BeaconConsumer {
    protected final String TAG = "Beacons Monitoring";
    private BeaconManager beaconManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        beaconManager = BeaconManager.getInstanceForApplication(this);
        beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24"));
        beaconManager.bind(this);
    }

    public void onDestroy(){
        super.onDestroy();
        beaconManager.unbind(this);
    }

    @Override
    public void onBeaconServiceConnect() {
        beaconManager.addMonitorNotifier(new MonitorNotifier() {
            @Override
            public void didEnterRegion(Region region) {
                Log.e(TAG,"I just saw a beacon for the first time");
            }

            @Override
            public void didExitRegion(Region region) {
                Log.e(TAG, "I lost my beacons :( ");
            }
            @Override
            public void didDetermineStateForRegion(int i, Region region) {
                Log.e(TAG, "I just switched from seeing/not seeing a beacon. STATE: " + i);
            }
        });
        try {
            beaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId", null, null, null));

        } catch (RemoteException e){
            Log.e(TAG, "EXCEPTION!!! :'( ");
        }
    }
}

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.michal.beacons2">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <uses-permission android:name="android.permission.BLUETOOTH"/>
        <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Does anyone know what could be wrong in my code?

2

2 Answers

6
votes

I managed to sort this out.

Firstly, is important to set beacons layout to the type of beacons you're using. These are the available layouts:

ALTBEACON       m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
EDDYSTONE TLM   x,s:0-1=feaa,m:2-2=20,d:3-3,d:4-5,d:6-7,d:8-11,d:12-15
EDDYSTONE UID   s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19
EDDYSTONE URL   s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-20v
IBEACON         m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24

SOURCE: https://beaconlayout.wordpress.com/

Layouts can be set using the following code:

beaconManager.getBeaconParsers().add(new 
BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));

Secondly, android requires location permissions to detect beacons. I have tested this by checking what happens with granted and denied permissions, but this requirement is also mentioned on Android Beacon Library website. I recommend following instructions on Google's Android Developer training regarding getting user's permission: https://developer.android.com/training/permissions/index.html

Moreover, I have tested the code provided by davidgyoung once I managed to sort this out and it does work the way described so I would suggest adding it to your code during the development phase.

All of this is actually clearly explained on Android Beacon Library website but I somehow confused everything. I hope this answer helps someone in the future.

1
votes

Understand that the didEnterRegion callback only fires if you are not already in the region. This means that if the beacon was transmitting when you restart the app during development, you won't get a new callback. You will always get a new callback to didDetermineStateForRegion() when the app restarts.

Why does it work this way? Because Android often temporarily kills apps due to low-memory conditions, and the library will restart them automatically a few minutes later to keep looking for beacons. If the library didn't work this way, the app would repeatedly get callbacks to didEnterRegion each time the app is temporarily stopped by Android OS, and later restarts, even though the beacon never disappeared and reappeared.

This can be frustrating during development, so it is possible to disable this feature with the following code:

beaconManager.setRegionStatePeristenceEnabled(false)

If you do this, it is probably wise to remove this line before going to production to prevent multiple entry events each time the app is temporarily killed by the OS.