I want to track the location of the user when a button on WebView is clicked. I'm using a background service so that it can track location in the background. The app should first request for location access. The code for service and location tracking was working when a button on activity was clicked. However, on button click in WebView, no dialog is shown for requesting permission.
Here's the code for WebView integration and start service
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Intent intent = new Intent(this.getApplication(), BackgroundLocationService.class);
this.getApplication().startService(intent);
this.getApplication().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
MyWebViewClient webViewClient = new MyWebViewClient(this);
webView.setWebViewClient(webViewClient);
webView.loadUrl("https://utopiaaa.000webhostapp.com/"); //just a sample website
}
Here's the code for service connection in MainActivity:
private ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
String name = className.getClassName();
if (name.endsWith("BackgroundLocationService")) {
Log.e("onServiceConnected","Let's see");
gpsService = ((BackgroundLocationService.LocationServiceBinder) service).getService();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
if (componentName.getClassName().equals("BackgroundLocationService")) {
gpsService = null;
}
}
@Override
public void onBindingDied(ComponentName name) {
}
@Override
public void onNullBinding(ComponentName name) {
}
};
Here's the code for requesting permission for location tracking access and to start tracking location:
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
gpsService.startTracking();
}
}
@Override
public void onLocationChanged(Location location) {
wayLatitude = location.getLatitude();
wayLongitude = location.getLongitude();
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.e("onLocationChanged",msg);
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
@RequiresApi(api = Build.VERSION_CODES.M)
public void startTracking() {
//check for permission
if (ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
Log.e("startTracking","Permission given");
gpsService.startTracking();
} else {
Log.e("startTracking","Permission denied");
ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION}, locationRequestCode);
}
}
And here's the code for WebView interface:
public class WebAppInterface {
/**
* Instantiate the interface and set the context
*/
WebAppInterface(Context c) {
mContext = c;
}
@JavascriptInterface
@RequiresApi(api = Build.VERSION_CODES.M)
public void TrackingOn() {
startTracking();
}
}
And here's the code for BackgroundLocationService:
public class BackgroundLocationService extends Service {
String date;
private final LocationServiceBinder binder = new LocationServiceBinder();
private static final String TAG = "BackgroundLocationServi";
private LocationListener mLocationListener;
private LocationManager mLocationManager;
private NotificationManager notificationManager;
public static final String CHANNEL_ID = "channel";
private FusedLocationProviderClient mFusedLocationClient;
private final int LOCATION_INTERVAL = 1000*60*10;
private final int LOCATION_DISTANCE = 1;
private final String URL_POST= "";
DateFormat df;
SimpleDateFormat simpleDateFormat;
private LocationRequest mLocationRequest;
LocationCallback locationCallback=new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
// do work here
onLocationChanged(locationResult.getLastLocation());
}
};
public BackgroundLocationService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.e("onStartCommand","Here");
return START_NOT_STICKY;
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
Log.i(TAG, "onCreate");
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
}
@Override
public void onDestroy() {
super.onDestroy();
if (mLocationManager != null) {
try {
mLocationManager.removeUpdates(mLocationListener);
} catch (Exception ex) {
Log.i(TAG, "fail to remove location listeners, ignore", ex);
}
}
}
public void onLocationChanged(Location location) {
Log.i(TAG, "LocationChanged: " + location);
date=df.format(location.getTime());
Toast.makeText(BackgroundLocationService.this, "LAT: " + location.getLatitude() + "\n LONG: " + location.getLongitude() + "\n" + date, Toast.LENGTH_SHORT).show();
}
@TargetApi(Build.VERSION_CODES.O)
@RequiresApi(api = Build.VERSION_CODES.M)
public void startTracking() {
startForeground(12345678, getNotification());
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(LOCATION_INTERVAL);
mLocationRequest.setFastestInterval(LOCATION_INTERVAL);
// Create LocationSettingsRequest object using location request
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
// Check whether location settings are satisfied
// https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
settingsClient.checkLocationSettings(locationSettingsRequest);
// new Google API SDK v11 uses getFusedLocationProviderClient(this)
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// Activity#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for Activity#requestPermissions for more details.
return;
}
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.requestLocationUpdates(mLocationRequest, locationCallback,
Looper.myLooper());
}
private void stopLocationUpdates() {
mFusedLocationClient.removeLocationUpdates(locationCallback);
}
public void stopTracking() {
stopLocationUpdates();
stopForeground(true);
this.onDestroy();
}
@RequiresApi(api = Build.VERSION_CODES.O)
private Notification getNotification() {
NotificationChannel channel = new NotificationChannel("channel_01", "My Channel", NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
Notification.Builder builder = new Notification.Builder(getApplicationContext(), "channel_01").setAutoCancel(true);
return builder.build();
}
public class LocationServiceBinder extends Binder {
public BackgroundLocationService getService() {
return BackgroundLocationService.this;
}
}
}
And here's the complete code for MainActivity:
public class MainActivity extends AppCompatActivity implements LocationListener{
public BackgroundLocationService gpsService;
private WebView webView;
private int locationRequestCode = 1000;
Context mContext;
private double wayLatitude = 0.0, wayLongitude = 0.0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Intent intent = new Intent(this.getApplication(), BackgroundLocationService.class);
this.getApplication().startService(intent);
this.getApplication().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
MyWebViewClient webViewClient = new MyWebViewClient(this);
webView.setWebViewClient(webViewClient);
webView.loadUrl("https://utopiaaa.000webhostapp.com/");
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && this.webView.canGoBack()) {
this.webView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
private ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
String name = className.getClassName();
if (name.endsWith("BackgroundLocationService")) {
gpsService = ((BackgroundLocationService.LocationServiceBinder) service).getService();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
if (componentName.getClassName().equals("BackgroundLocationService")) {
gpsService = null;
}
}
@Override
public void onBindingDied(ComponentName name) {
}
@Override
public void onNullBinding(ComponentName name) {
}
};
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
gpsService.startTracking();
}
}
@Override
public void onLocationChanged(Location location) {
wayLatitude = location.getLatitude();
wayLongitude = location.getLongitude();
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.e("onLocationChanged",msg);
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
public class WebAppInterface {
/**
* Instantiate the interface and set the context
*/
WebAppInterface(Context c) {
mContext = c;
}
@JavascriptInterface
@RequiresApi(api = Build.VERSION_CODES.M)
public void TrackingOn() {
startTracking();
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
public void startTracking() {
//check for permission
if (ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
gpsService.startTracking();
} else {
ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION}, locationRequestCode);
}
}
}