Simple Distance Detection Android App

Hello,

I have no idea how to start this. I want an app to print the distances between my android phone and the beacons. That’s all I want. I have an account, and estimote location beacons, but I don’t know how to run an app that I create on the the cloud. (heypiotr, if you see this, could really use some help).

Thanks,
RAMSEE

Hi @Gamma2,

you want to print a distance, so you need the ranging technology.

  • the ranging technology is used in the foreground of your activity,
  • it takes a BeaconRegion in argument to know how beacons to search,
  • it continuously scans (1s by default) the beacons of the region and send you a list of Beacon objects,
  • it drains more battery than the monitring technology.
How to range a region?

class MyRangingActivity {
    private BeaconManager beaconManager;
    private BeaconRegion beaconRegion;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Get a new BeaconManager instance.
        this.beaconManager = new BeaconManager(this);

        // Set up a ranging listener.
        this.beaconManager.setRangingListener( new BeaconManager.BeaconRangingListener() {
            @Override
            public void onBeaconsDiscovered(BeaconRegion region, List<Beacon> list) {
                // Handle here the discovered beacons list of the region.
                // You can for example calculate the distance with the RSSI.
                // You can also get the proximity value with RegionUtils.computeProximity().
            }
        });

        // Create a new BeaconRegion instance to range.
        this.beaconRegion = new BeaconRegion(<identifier>, <proximityUUID>, <major>, <minor>);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Checks automatically the permissions before ranging.
        SystemRequirementsChecker.checkWithDefaultDialogs(this);

        // Starts ranging after being connected to the BeaconService.
        this.beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
            @Override
            public void onServiceReady() {
                beaconManager.startRanging(beaconRegion);
            }
        });
    }

    @Override
    protected void onPause() {
        // Ranging is on foreground only, so stop it when activity is paused.
        this.beaconManger.stopRanging(this.beaconRegion);

        super.onPause();
    }

    @Override
    protected void onDestroy() {
        // Disconnect from BeaconService when not used.
        this.beaconManager.disconnect();

        super.onStop();
    }
}

Hi Ximun,

I tried a different way, but I’m not getting the refresh rate that I would like. When I tried created another class the way described, for some reason the app crashes when I startActivity(intent) on that activity.

Here is my MainActivity that runs on startup. when i comment out the startActivity(intent), this works, but not accurately:

imports
//
// Running into any issues? Drop us an email to: contact@estimote.com
//

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

private static final Map<Color, Integer> BACKGROUND_COLORS = new HashMap<>();

static {
    BACKGROUND_COLORS.put(Color.ICY_MARSHMALLOW, android.graphics.Color.rgb(109, 170, 199));
    BACKGROUND_COLORS.put(Color.BLUEBERRY_PIE, android.graphics.Color.rgb(98, 84, 158));
    BACKGROUND_COLORS.put(Color.MINT_COCKTAIL, android.graphics.Color.rgb(155, 186, 160));
}

private static final int BACKGROUND_COLOR_NEUTRAL = android.graphics.Color.rgb(160, 169, 172);

private ProximityContentManager proximityContentManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Intent intent = new Intent(this, MyRangingActivity.class);
    //startActivity(intent);


    proximityContentManager = new ProximityContentManager(this,
            Arrays.asList(
                    new BeaconID("B9407F30-F5F8-466E-AFF9-25556B57FE6D", 45640, 7091),
                    new BeaconID("B9407F30-F5F8-466E-AFF9-25556B57FE6D", 16197, 22552),
                    new BeaconID("B9407F30-F5F8-466E-AFF9-25556B57FE6D", 21615, 27985)),
            new EstimoteCloudBeaconDetailsFactory());

    proximityContentManager.setListener(new ProximityContentManager.Listener() {
        @Override
        public void onContentChanged(Object content) {
            String text = "";
            Integer backgroundColor;
            if (content != null) {
                EstimoteCloudBeaconDetails beaconDetails = (EstimoteCloudBeaconDetails) content;
                double distance = proximityContentManager.get_dist();
                //text = "You're in " + beaconDetails.getBeaconName() + "'s range!";
                //text += "" + beaconDetails.getBeaconName() + " is " + distance + " away. ";
                backgroundColor = BACKGROUND_COLORS.get(beaconDetails.getBeaconColor());
                List<Beacon> beacons = proximityContentManager.get_beacons();
                text += "There are " + beacons.size() + " beacons detected.\n";
                for (Beacon beacon : beacons){
                    distance = Math.pow(10, (beacon.getMeasuredPower() - beacon.getRssi())/20.0);
                    text += "A beacon is " + distance + "m away. \n";
                }

            } else {
                text += "No beacons in range.";
                backgroundColor = null;
            }
            ((TextView) findViewById(R.id.textView)).setText(text);
            findViewById(R.id.relativeLayout).setBackgroundColor(
                    backgroundColor != null ? backgroundColor : BACKGROUND_COLOR_NEUTRAL);

        }
    });
    //
}

@Override
protected void onResume() {
    super.onResume();

    if (!SystemRequirementsChecker.checkWithDefaultDialogs(this)) {
        Log.e(TAG, "Can't scan for beacons, some pre-conditions were not met");
        Log.e(TAG, "Read more about what's required at: http://estimote.github.io/Android-SDK/JavaDocs/com/estimote/sdk/SystemRequirementsChecker.html");
        Log.e(TAG, "If this is fixable, you should see a popup on the app's screen right now, asking to enable what's necessary");
    } else {
        Log.d(TAG, "Starting ProximityContentManager content updates");
        proximityContentManager.startContentUpdates();
    }
}

@Override
protected void onPause() {
    super.onPause();
    Log.d(TAG, "Stopping ProximityContentManager content updates");
    proximityContentManager.stopContentUpdates();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    proximityContentManager.destroy();
}

}

and here is the Ranging activity:

imports

public class MyRangingActivity extends MainActivity {
private BeaconManager beaconManager;
private BeaconRegion beaconRegion;

@Override
protected void onCreate(Bundle savedInstanceState) {
    //super.onCreate(savedInstanceState);

    // Get a new BeaconManager instance.
    this.beaconManager = new BeaconManager(this);


    // Set up a ranging listener.
    this.beaconManager.setRangingListener(new BeaconManager.BeaconRangingListener() {
        String text = "";
        double distance = 0.0;

        @Override
        public void onBeaconsDiscovered(BeaconRegion region, List<Beacon> list) {
            // Handle here the discovered beacons list of the region.
            // You can for example calculate the distance with the RSSI.
            // You can also get the proximity value with RegionUtils.computeProximity().
            for (Beacon beacon : list) {
                distance = Math.pow(10, (beacon.getMeasuredPower() - beacon.getRssi()) / 20.0);
                text += "A beacon is " + distance + "m away. \n";
            }
        }

        TextView theactualtext = (TextView) findViewById(R.id.textView);
        //((TextView) findViewById(R.id.textView)).setText(text);

    });

    // Create a new BeaconRegion instance to range.
    //this.beaconRegion = new BeaconRegion(<identifier>, <proximityUUID>, <major>, <minor>);
}

@Override
protected void onResume() {
    super.onResume();

    // Checks automatically the permissions before ranging.
    SystemRequirementsChecker.checkWithDefaultDialogs(this);

    // Starts ranging after being connected to the BeaconService.
    this.beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
        @Override
        public void onServiceReady() {
            beaconManager.startRanging(beaconRegion);
        }
    });
}

@Override
protected void onPause() {
    // Ranging is on foreground only, so stop it when activity is paused.
    this.beaconManager.stopRanging(this.beaconRegion);

    super.onPause();
}

@Override
protected void onDestroy() {
    // Disconnect from BeaconService when not used.
    this.beaconManager.disconnect();

    super.onStop();
}

@Override
public void onStart() {
    super.onStart();
}

@Override
public void onStop() {
    super.onStop();
}

}

Could you tell me what I am doing wrong? Android studio won’t let me setText to the textview either. Don’t know what that issue is either.

Hey,

why do you extend the MainActivity class and create an Intent for the new class?
Can’t you simply change the AndroidManifest.xml file to launch directly your MyRangingActivity class?

The problem is if you extend the activity you need all the class used…
Could you just try with my code snippet to see if it works?
Handling the onBeaconsDiscovered() method to display with a simple layout.

If you success, you will have to prepare a beacon cache not to display the same beacon each time you get a notification.