First time I run the app beacon monitoring and ranging is working fine. But the second time I lanuch the app i.e after calling onResume it is only showing following and no more calls to didRangeBeaconsInRegion : I am guessing it is because of beaconManager instance is not properly destroyed or something in calls to onDestroy. However according to the library example I tried unbinding in onPause() with no success. Any idea ?
I/MonitoringActivity: I have just switched from seeing/not seeing beacons: 0
2020-07-15 18:41:40.776 9657-9657/com.something.beacon I/MonitoringActivity: I have just switched from seeing/not seeing beacons: 0
2020-07-15 18:41:40.824 9657-9657/com.something.beacon I/MonitoringActivity: I have just switched from seeing/not seeing beacons: 1
public class MainActivity extends AppCompatActivity implements BeaconConsumer {
private static final int PERMISSION_REQUEST_FINE_LOCATION = 1;
private static final int PERMISSION_REQUEST_BACKGROUND_LOCATION = 2;
ListView beaconList;
protected static final String TAG = "MonitoringActivity";
private BeaconManager beaconManager;
private FirebaseDatabase database;
private DatabaseReference beaconDBRef;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Firebase database setup
database = FirebaseDatabase.getInstance();
beaconDBRef = database.getReference().child("messages");
beaconList = (ListView) findViewById(R.id.beacon_list);
Log.d(TAG, "onCreate: is called");
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
// Detect the main identifier (UID) frame:
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT));
// Detect the telemetry (TLM) frame:
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(BeaconParser.EDDYSTONE_TLM_LAYOUT));
// Detect the URL frame:
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT));
beaconManager.bind(this);
verifyBluetooth();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (this.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (this.checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (!this.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs background location access");
builder.setMessage("Please grant location access so this app can detect beacons in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#TargetApi(23)
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION},
PERMISSION_REQUEST_BACKGROUND_LOCATION);
}
});
builder.show();
}
else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since background location access has not been granted, this app will not be able to discover beacons in the background. Please go to Settings -> Applications -> Permissions and grant background location access to this app.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
}
}
} else {
if (!this.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION},
PERMISSION_REQUEST_FINE_LOCATION);
}
else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons. Please go to Settings -> Applications -> Permissions and grant location access to this app.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
}
}
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onDestroy() {
super.onDestroy();
beaconManager.unbind(this);
}
long tempTime = Integer.MIN_VALUE;
long callInterval = 10000;
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_FINE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "fine location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover nearby devices.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
case PERMISSION_REQUEST_BACKGROUND_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "background location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since background location access has not been granted, this app will not be able to discover devices when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
private void verifyBluetooth() {
try {
if (!BeaconManager.getInstanceForApplication(this).checkAvailability()) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth not enabled");
builder.setMessage("Please enable bluetooth in settings and restart this application.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
//finish();
//System.exit(0);
}
});
builder.show();
}
}
catch (RuntimeException e) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Bluetooth LE not available");
builder.setMessage("Sorry, this device does not support Bluetooth LE.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
//finish();
//System.exit(0);
}
});
builder.show();
}
}
#Override
public void onBeaconServiceConnect() {
// Set the two identifiers below to null to detect any beacon regardless of identifiers
Identifier myBeaconNamespaceId = Identifier.parse("0x2F234454F4911BA9FFA6");
final Identifier myBeaconInstanceId = Identifier.parse("0x000000000001");
beaconManager.removeAllMonitorNotifiers();
beaconManager.removeAllRangeNotifiers();
beaconManager.addMonitorNotifier(new MonitorNotifier() {
#Override
public void didEnterRegion(Region region) {
Log.i(TAG, "I just saw an beacon for the first time!");
try {
Log.d(TAG, "didEnterRegion");
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void didExitRegion(Region region) {
Log.i(TAG, "I no longer see an beacon");
try {
Log.d(TAG, "didExitRegion");
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void didDetermineStateForRegion(int state, Region region) {
Log.i(TAG, "I have just switched from seeing/not seeing beacons: "+state);
}
});
beaconManager.addRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for(Beacon oneBeacon : beacons) {
String beaconInfo = "Namespace id: " + oneBeacon.getId1() + "\nInstance Id: " + oneBeacon.getId2();
Log.d(TAG, beaconInfo);
Toast.makeText(MainActivity.this, beaconInfo, Toast.LENGTH_SHORT).show();
//Write to database every 10 seconds
long currentTime = System.currentTimeMillis();
if(currentTime > tempTime + callInterval){
BeaconModel beaconModel = new BeaconModel();
beaconModel.setBeaconName(oneBeacon.getId2().toString());
beaconModel.setDistance(oneBeacon.getDistance());
beaconModel.setMessage("this is a nice message");
beaconDBRef.child(beaconModel.getBeaconName()).setValue(beaconModel);
//beaconDBRef.push().setValue("beacon detected! - " + oneBeacon.getId2());
tempTime = currentTime;
}
}
}
});
try {
Identifier myBeaconNamespaceId1 = Identifier.parse("0xedd1ebeac04e5defa017");
Identifier myBeaconInstanceId1 = Identifier.parse("0x0e32fea91b13");
Identifier myBeaconInstanceId2 = Identifier.parse("0xa9937b420872");
beaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId", myBeaconNamespaceId1, myBeaconInstanceId1, null));
beaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId2", myBeaconNamespaceId1, myBeaconInstanceId2, null));
beaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId3", null, null, null));
} catch (RemoteException e) {
Log.d(TAG, e.getMessage());
}
}
}
Related
I'me trying to create a simple BLE application on my Android phone.
I've tried a lot of example without success, i must forget something.
Hope you could help me.
First you'll find the permissions added and then my simple activy
Permissions:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
And my activity :
Two button, one to execute a Scan and another to stop it.
I'd like to detecte an BLE device, but nothing is never detected with my code.
public class MainActivity extends AppCompatActivity {
BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;
Button startScanningButton;
Button stopScanningButton;
TextView peripheralTextView;
private final static int REQUEST_ENABLE_BT = 1;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView);
peripheralTextView.setMovementMethod(new ScrollingMovementMethod());
startScanningButton = (Button) findViewById(R.id.StartScanButton);
startScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startScanning();
}
});
stopScanningButton = (Button) findViewById(R.id.StopScanButton);
stopScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
stopScanning();
}
});
stopScanningButton.setVisibility(View.INVISIBLE);
btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = BluetoothAdapter.getDefaultAdapter();
if ( btAdapter == null ) {
Toast.makeText(
this,
"Bluetooth not supported on this deveice",
Toast.LENGTH_LONG).show();
return;
}
btScanner = btAdapter.getBluetoothLeScanner();
btScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (btAdapter == null || !btAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
if ( ! btAdapter.isEnabled() ) {
// Demande à activer l'interface bluetooth
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
if ( checkSelfPermission( Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED ) {
requestPermissions(
new String[] { android.Manifest.permission.ACCESS_COARSE_LOCATION },
456 );
}
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
}
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect peripherals.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
private ScanCallback leScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
peripheralTextView.append("Device Name: " + result.getDevice().getName() + " rssi: " + result.getRssi() + "\n");
super.onScanResult(callbackType, result);
final int scrollAmount = peripheralTextView.getLayout().getLineTop(peripheralTextView.getLineCount()) - peripheralTextView.getHeight();
if (scrollAmount > 0)
peripheralTextView.scrollTo(0, scrollAmount);
}
};
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
System.out.println("coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
private boolean mScanning = false;
private Handler handler = new Handler();
private static final long SCAN_PERIOD = 30000;
public void startScanning() {
System.out.println("start scanning");
peripheralTextView.setText("");
startScanningButton.setVisibility(View.INVISIBLE);
stopScanningButton.setVisibility(View.VISIBLE);
if (!mScanning) {
// Stops scanning after a pre-defined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
btScanner.stopScan(leScanCallback);
System.out.println("stop scanning");
}
}, SCAN_PERIOD);
mScanning = true;
btScanner.startScan(leScanCallback);
System.out.println("restart scanning");
} else {
mScanning = false;
btScanner.stopScan(leScanCallback);
System.out.println("stop scanning");
}
}
public void stopScanning() {
System.out.println("stopping scanning");
peripheralTextView.append("Stopped Scanning");
startScanningButton.setVisibility(View.VISIBLE);
stopScanningButton.setVisibility(View.INVISIBLE);
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.stopScan(leScanCallback);
}
});
}
}
I never scan nothing..
Totaly newby, thanks a lot for your help.
Regards
You also need to have ACCESS_BACKGROUND_LOCATION declared in order to find other Bluetooth devices. You can find more information here:-
https://developer.android.com/guide/topics/connectivity/bluetooth#Permissions
Bluetooth LE Scan fails in the background - permissions
Turn on Android LE scanning without asking user for permission
And the links below are useful for getting started with Android LE Development:-
The Ultimate Guide to Android BLE Development
Android Lollipop: Bluetooth LE Matures
Bluetooth LE Send String Data between Devices
I want to be able to scan for BLE tags in the background.
I have read about using Services to do this. However, when the service is executed and then I run another application on my phone, the BLE scan callback stops executing but the service still runs as normal.
I know the BLE callback stops because the log cat stops producing the log data until I open the application again.
Below is my MainActiivity:
public class MainActivity extends AppCompatActivity {
BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;
Button startScanningButton;
Button stopScanningButton;
TextView peripheralTextView;
private NotificationManagerCompat notificationManager;
private final static int REQUEST_ENABLE_BT = 1;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
private static final String TAG = "ExampleJobService";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate MAIN");
notificationManager = NotificationManagerCompat.from(this);
peripheralTextView = (TextView) findViewById(R.id.PeripheralTextView);
peripheralTextView.setMovementMethod(new ScrollingMovementMethod());
startScanningButton = (Button) findViewById(R.id.StartScanButton);
startScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d(TAG, "Start button");
startService(new Intent(MainActivity.this, ExampleService.class));
}
});
stopScanningButton = (Button) findViewById(R.id.StopScanButton);
stopScanningButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.d(TAG, "Stop 1");
Intent serviceIntent = new Intent(MainActivity.this, ExampleService.class);
stopScanning();
stopService(serviceIntent);
Log.d(TAG, "Stop 2");
}
});
btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
btScanner = btAdapter.getBluetoothLeScanner();
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
}
// Make sure we have access coarse location enabled, if not, prompt the user to enable it
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect peripherals.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
System.out.println("coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
public void startScanning() {
peripheralTextView.setText("");
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.startScan(leScanCallback);
}
});
}
public void stopScanning() {
System.out.println("stopping scanning");
peripheralTextView.append("Stopped Scanning");
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.stopScan(leScanCallback);
}
});
}
}
Below is the ExampleService:
public class ExampleService extends Service {
BluetoothManager btManager;
BluetoothAdapter btAdapter;
BluetoothLeScanner btScanner;
TextView peripheralTextView;
private NotificationManagerCompat notificationManager;
private static final String TAG = "ExampleJobService";
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
btManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
btScanner = btAdapter.getBluetoothLeScanner();
//do heavy work on a background thread
AsyncTask.execute(new Runnable() {
#Override
public void run() {
btScanner.startScan(leScanCallback);
}
});
return START_REDELIVER_INTENT;
}
private ScanCallback leScanCallback = new ScanCallback() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.d(TAG, "BLE executed");
if(result.getDevice().getAddress().equals("EE:7E:DE:9B:65:46") && result.getRssi() > -80){
Log.d(TAG, "Tag found");
}
}
};
#Override
public void onDestroy() {
Log.d(TAG, "Destroy");
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
EDIT 1:
String[] peripheralAddresses = new String[]{"EE:7E:DE:9B:65:46"};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Example Service")
.setContentText("input")
.setSmallIcon(R.drawable.ic_one)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.build();
// Build filters list
List<ScanFilter> filters = null;
if (peripheralAddresses != null) {
filters = new ArrayList<>();
for (String address : peripheralAddresses) {
ScanFilter filter = new ScanFilter.Builder()
.setDeviceAddress(address)
.build();
filters.add(filter);
}
}
btScanner.startScan(filters, settings, leScanCallback);
return START_STICKY;
}
First, I recommend you to add Scan filters, because Android stops scan after some time if you scan without them.
Second, Your service will not live for a long time, because Android will kill it, if your device's Android versions is more or equal Android Oreo (Android 8).
So I recommend you to read this article for finding better solution.
Hope, this will help you!
From past few days I am looking for a solution but unable to find any. I am working on a situation when the google location accuracy is toggled off for android 9+ then the application should prompt user to toggle on the location accuracy.
Problem facing:
Is it possible if (statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) then navigate directly to google location accuracy screen of the device(which looks difficult). OR customise the dialog box which is prompted by google services library (which is not possible i assume). Any thoughts would be appreciated.
Below is the snippet.
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(UPDATE_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
mLocationSettingsRequest = builder.build(); mSettingsClient.checkLocationSettings(mLocationSettingsRequest).addOnSuccessListener(mActivity,
new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
mFusedProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper()).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
}
});
}
}).addOnFailureListener(mActivity, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
int statusCode = ((ApiException) e).getStatusCode();
if(statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED){
//Location settings not satisfied.
try {
ResolvableApiException resolvable = (ResolvableApiException) e;
resolvable.startResolutionForResult(
mActivity,
LOCATION_REQUEST);
} catch (IntentSender.SendIntentException ex) {
}
} else {
}
}
});
Try this,works for me
private void showLocationDialog() {
new AlertDialog.Builder(RequestLocationUpdatesWithIntentActivity.this).setTitle("The location service is not enabled on the phone.")
.setMessage("Go to Settings > Location information (enable location service).")
.setNegativeButton("cancels", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setPositiveButton("Unset", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
RequestLocationUpdatesWithIntentActivity.this.startActivity(intent);
} catch (ActivityNotFoundException ex) {
intent.setAction(Settings.ACTION_SETTINGS);
try {
RequestLocationUpdatesWithIntentActivity.this.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
})
.show();
}
You can call it here.
And then there's this effect.
I am trying to develop an Android app capable to connect to a BLE device. But i have a problem to find ble devices. The scanLeDevice methods run but I have no callback. You can find my code below: I use Log.i() to display ble devices.
With another app (downloaded from the store) I can find my ble device and others bluetooth around. So It's not my phone's problem.
Thanks for help!
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter bluetoothAdapter;
private final int REQUEST_ENABLE_BT = 1;
private boolean mScanning;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("MainActivity", "Begin");
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Log.i("MainActivity", "End for permissions");
if(Build.VERSION.SDK_INT < 21){
scanLeDevice(true);
}else{
scanDevice(true);
}
}
private Handler handler = new Handler();
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
bluetoothAdapter.stopLeScan(leScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
bluetoothAdapter.startLeScan(leScanCallback);
Log.i("MainActivity", "scanning");
} else {
mScanning = false;
bluetoothAdapter.stopLeScan(leScanCallback);
}
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback leScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//Ici///////////////////////////////////////
Log.i("MainActivity", "Nam: "+device.getName()+" Adresse: "+device.getAddress());
if(device.getName() != null && device.getName().equals("RN4871-85D7"))
scanLeDevice(false);
}
});
}
};
///////////////////Scan for API 21
private ScanSettings settings;
private List<ScanFilter> filters;
private BluetoothLeScanner mLEScanner;
private void scanDevice(final boolean enable){
if (mLEScanner==null){
mLEScanner = bluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
filters = new ArrayList<ScanFilter>();
}
if (enable) {
if (mScanning) return;
// Stops scanning after a pre-defined scan period.
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (!mScanning) return;
try {
mScanning = false;
//Log.d("MainActivity","STOP SCAN AFTER DELAY");
mLEScanner.stopScan(mScanCallback);
Log.i("MainActivity", "stop scanning API 21");
} catch (Exception e){Log.e("MainActivity",e.getMessage());}
}
}, SCAN_PERIOD);
mScanning = true;
//Log.d("MainActivity","START SCAN FROM EXPLICIT CALL");
mLEScanner.startScan(filters, settings, mScanCallback);
Log.i("MainActivity", "scanning API 21");
} else if (mLEScanner!=null){
if (!mScanning) return;
mScanning = false;
try {
//Log.d("MainActivity","STOP SCAN FROM EXPLICIT CALL");
mLEScanner.stopScan(mScanCallback);
Log.i("MainActivity", "stop scanning API 21");
} catch (Exception e){Log.i("MainActivity",e.getMessage());}
}
}
//call back for API 21
//#TargetApi(21)
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.i("MainActivity", "onScanResult API 21");
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.i("MainActivity", "onBatchScanResults API 21");
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.i("MainActivity", "onScanFailed API 21");
}
};
}
Thanks for your help``
I found what was the problem about the location.
In fact, if you work with a API >= 23, you have to authorize you app to access to the location (not only in the Manifest file, but in you code it self).
So if you have the same problem:
First, manualy, go to your phon's setting and autorize your app to access to location: to be sure that was the problem.
Then add the code below so that, The application ask the user to authorize the application to access the location
/////////////////////////Location/////
#TargetApi(Build.VERSION_CODES.M)
private void loadPermissions(String perm,int requestCode) {
if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, perm)) {
ActivityCompat.requestPermissions(this, new String[]{perm},requestCode);
}
} else if (checkLocationEnabled())
initScanner();
}
private boolean checkLocationEnabled(){
LocationManager lm = (LocationManager)this.getSystemService(Context.LOCATION_SERVICE);
boolean gps_enabled = false;
boolean network_enabled = false;
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch(Exception ex) {}
try {
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch(Exception ex) {}
if(!gps_enabled && !network_enabled) {
// notify user
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setMessage("GPS desabled");
dialog.setPositiveButton("Open GPS settings", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
// TODO Auto-generated method stub
Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(myIntent);
//get gps
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface paramDialogInterface, int paramInt) {
// TODO Auto-generated method stub
}
});
dialog.show();
return false;
} else return true;
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_FINE_LOCATION: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// granted
if (checkLocationEnabled())
initScanner();
}
else{
// no granted
}
return;
}
}
}
I had this problem too because I was using ACCESS_COARSE_LOCATION on the permission.
When I changed to ACCESS_FINE_LOCATION, it finally works for me!
I have a saved geo location(latitude,longitude).when a user presses a action button in app, the current location is recorded.
I want to check if the current latitude,longitude(which I have) falls
in a circular geofence (who's center geo point I have ).
I don't want to create a geofence on Google map. I just want to check if a geolocation falls in a geofence.
The code I use to get current geolocation when the accuracy is less than 20 :
public class CreatePlaceActivity extends Fragment implements
OnClickListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private Button cancelBtn, submitBtn;
public boolean geoLocationCheck = false;
private String TAG = "CreatePlaceActivity";
public CreatePlaceActivity() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.create_place_screen,
container, false);
submitBtn = (Button) rootView.findViewById(R.id.submit_btn_id);
submitBtn.setTypeface(typeface);
submitBtn.setOnClickListener(this);
cancelBtn = (Button) rootView.findViewById(R.id.cancel_btn_id);
cancelBtn.setOnClickListener(this);
setlocationClient();
return rootView;
}
private void setlocationClient() {
int resp = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(getActivity());
if (resp == ConnectionResult.SUCCESS) {
locationclient = new GoogleApiClient.Builder(getActivity())
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
locationclient.connect();
} else {
GooglePalyErrorDialogIsShowing = true;
Toast.makeText(getActivity(),// CreatePlaceActivity.this,
"Google Play Service Error " + resp, Toast.LENGTH_LONG)
.show();
if (alert == null) {
onLocationChangedbuilder = new AlertDialog.Builder(
getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
} else if (alert.isShowing()) {
alert.dismiss();
onLocationChangedbuilder = new AlertDialog.Builder(
getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
}
onLocationChangedbuilder
.setTitle("Alert!")
.setMessage("Google Play Service Error " + resp)
.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
locationLockDialogIsShowing = false;
GooglePalyErrorDialogIsShowing = false;
((MenuActivity) getActivity())
.removeFragment(CreatePlaceActivity.this);
}
});
alert = onLocationChangedbuilder.create();
alert.setCancelable(false);
try {
alert.show();
} catch (Exception e) {
}
}
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.submit_btn_id:
Log.i(TAG, "lat=" + currentGeoLocation.getLatitude() + "lon="
+ currentGeoLocation.getLongitude() + "acc="
+ currentGeoLocation.getAccuracy() + "alt="
+ currentGeoLocation.getAltitude());
validatePlace();
break;
case R.id.cancel_btn_id:
// finish();
((MenuActivity) getActivity())
.removeFragment(CreatePlaceActivity.this);
break;
default:
break;
}
}
#Override
public void onLocationChanged(Location location) {
float accuracy = 50;
// DateTime dt1 = new DateTime();
// DateTimeFormatter fmt1 = ISODateTimeFormat.dateTime();
Time time = new Time();
time.setToNow();
String strdt = String.valueOf(time.toMillis(false));
if (location != null) {
accuracy = location.getAccuracy();
locationLockDialogIsShowing = true;
if (globalAccuracy - location.getAccuracy() >= 20
|| globalAccuracy - location.getAccuracy() >= -20) {
globalAccuracy = location.getAccuracy();
}
}
if (alert == null) {
onLocationChangedbuilder = new AlertDialog.Builder(getActivity(),
AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
} else if (alert.isShowing()) {
alert.dismiss();
onLocationChangedbuilder = new AlertDialog.Builder(getActivity(),
AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
}
final float accr = accuracy;
onLocationChangedbuilder
.setTitle("Alert!")
.setMessage(
"Getting the best possible location..Please wait.\nCurrent Accuracy is "
+ accuracy)
.setPositiveButton("Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
locationLockDialogIsShowing = false;
if (locationclient != null) {
locationclient.disconnect();
}
Time time = new Time();
time.setToNow();
String strdt = String.valueOf(time
.toMillis(false));
if (alert == null) {
} else if (alert.isShowing()) {
alert.dismiss();
}
if (locationLockAlert == null) {
} else if (locationLockAlert.isShowing()) {
locationLockAlert.dismiss();
}
// setResult(RESULT_OK);
// finish();
((MenuActivity) getActivity())
.removeFragment(CreatePlaceActivity.this);
}
});
alert = onLocationChangedbuilder.create();
alert.setCancelable(false);
try {
alert.show();
} catch (Exception e) {
}
if (location.getAccuracy() <= 16) {
DateTime dt = new DateTime();
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
String str1 = fmt.print(dt);
locationLockDialogIsShowing = false;
Time timeNow = new Time();
timeNow.setToNow();
String str = String.valueOf(timeNow.toMillis(false));
// locationLockTimestamp = str1;
// TODO
currentGeoLocation = location;
if (locationclient != null) {
if (locationclient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(
locationclient, this);
locationclient.disconnect();
}
}
if (alert.isShowing()) {
alert.dismiss();
}
if (locationLockAlert != null) {
if (locationLockAlert.isShowing()) {
locationLockAlert.dismiss();
}
}
showDialog("Alert!",
"GPS Location locked.. You can now continue to create place");
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// TODO Auto-generated method stub
}
#Override
public void onConnected(Bundle connectionHint) {
// TODO Auto-generated method stub
final float accuracy = 250;
if (locationclient != null && locationclient.isConnected()) {
if (geoLocationCheck == false) {
locationrequest = LocationRequest.create();
locationrequest
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationrequest.setInterval(100);
// locationclient.requestLocationUpdates(locationrequest, this);
LocationServices.FusedLocationApi.requestLocationUpdates(
locationclient, locationrequest, this);
locationLockDialogIsShowing = true;
if (alert == null) {
onLocationChangedbuilder = new AlertDialog.Builder(
getActivity(),
AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
} else if (alert.isShowing()) {
alert.dismiss();
onLocationChangedbuilder = new AlertDialog.Builder(
getActivity(),
AlertDialog.THEME_DEVICE_DEFAULT_LIGHT);
}
onLocationChangedbuilder
.setTitle("Alert!")
.setMessage(
"Getting the best possible location..Please wait.\nCurrent Accuracy is "
+ accuracy)
.setPositiveButton("Cancel",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
locationLockDialogIsShowing = false;
if (locationclient != null) {
locationclient.disconnect();
}
Time time = new Time();
time.setToNow();
String strdt = String.valueOf(time
.toMillis(false));
if (alert == null) {
} else if (alert.isShowing()) {
alert.dismiss();
}
if (locationLockAlert == null) {
} else if (locationLockAlert
.isShowing()) {
locationLockAlert.dismiss();
}
// setResult(RESULT_OK);
// finish();
((MenuActivity) getActivity())
.removeFragment(CreatePlaceActivity.this);
}
});
alert = onLocationChangedbuilder.create();
alert.setCancelable(false);
try {
alert.show();
} catch (Exception e) {
}
}
}
}
#Override
public void onConnectionSuspended(int arg0) {
Log.i("fused", "loc client onConnectionSuspended");
}
public Dialog showDialog(String title, String msg) {
locationLockAlert = new AlertDialog.Builder(getActivity(),
AlertDialog.THEME_DEVICE_DEFAULT_LIGHT).create();
locationLockAlert.setTitle(title);
locationLockAlert.setMessage(msg);
locationLockAlert.setButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
locationLockAlert.dismiss();
}
});
try {
locationLockAlert.show();
} catch (Exception e) {
}
return locationLockAlert;
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// TODO Auto-generated method stub
}
}
Link I have referred is Android Geofencing (Polygon)
Thanks!
If you know the radius of the circle and its center point, you know if any other point is inside the circle by using the following formula:
which is the distance formula.
Also, if both points are Location objects. you can use Location.distanceTo