1. Add dependencies
dependencies {
//location service implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.google.android.material:material:1.0.0'}
2. Main activity
create new class
MainActivity class
======================================
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.Manifest;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;
public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = MainActivity.class.getSimpleName();
// Used in checking for runtime permissions. private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
// The BroadcastReceiver used to listen from broadcasts from the service. private MyReceiver myReceiver;
// A reference to the service used to get location updates. private LocationService mService = null;
// Tracks the bound state of the service. private boolean mBound = false;
// UI elements. private Button mRequestLocationUpdatesButton;
private Button mRemoveLocationUpdatesButton;
// Monitors the state of the connection to the service. private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
LocationService.LocalBinder binder = (LocationService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
};
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myReceiver = new MyReceiver();
setContentView(R.layout.activity_main);
// Check that the user hasn't revoked permissions by going to Settings. if (Utils.requestingLocationUpdates(this)) {
if (!checkPermissions()) {
requestPermissions();
}
}
}
@Override protected void onStart() {
super.onStart();
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this);
mRequestLocationUpdatesButton = (Button) findViewById(R.id.request_location_updates_button);
mRemoveLocationUpdatesButton = (Button) findViewById(R.id.remove_location_updates_button);
mRequestLocationUpdatesButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
if (!checkPermissions()) {
requestPermissions();
} else {
mService.requestLocationUpdates();
}
}
});
mRemoveLocationUpdatesButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
mService.removeLocationUpdates();
}
});
// Restore the state of the buttons when the activity (re)launches. setButtonsState(Utils.requestingLocationUpdates(this));
// Bind to the service. If the service is in foreground mode, this signals to the service // that since this activity is in the foreground, the service can exit foreground mode. bindService(new Intent(this, LocationService.class), mServiceConnection,
Context.BIND_AUTO_CREATE);
}
@Override protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver,
new IntentFilter(LocationService.ACTION_BROADCAST));
}
@Override protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
super.onPause();
}
@Override protected void onStop() {
if (mBound) {
// Unbind from the service. This signals to the service that this activity is no longer // in the foreground, and the service can respond by promoting itself to a foreground // service. unbindService(mServiceConnection);
mBound = false;
}
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(this);
super.onStop();
}
/** * Returns the current state of the permissions needed. */ private boolean checkPermissions() {
return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION);
}
private void requestPermissions() {
boolean shouldProvideRationale =
ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION);
// Provide an additional rationale to the user. This would happen if the user denied the // request previously, but didn't check the "Don't ask again" checkbox. if (shouldProvideRationale) {
Log.i(TAG, "Displaying permission rationale to provide additional context.");
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
@Override public void onClick(View view) {
// Request permission ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
}
})
.show();
} else {
Log.i(TAG, "Requesting permission");
// Request permission. It's possible this can be auto answered if device policy // sets the permission in a given state or the user denied the permission // previously and checked "Never ask again". ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
}
}
/** * Callback received when a permissions request has been completed. */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
Log.i(TAG, "onRequestPermissionResult");
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
if (grantResults.length <= 0) {
// If user interaction was interrupted, the permission request is cancelled and you // receive empty arrays. Log.i(TAG, "User interaction was cancelled.");
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission was granted. mService.requestLocationUpdates();
} else {
// Permission denied. setButtonsState(false);
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_denied_explanation,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.settings, new View.OnClickListener() {
@Override public void onClick(View view) {
// Build intent that displays the App settings screen. Intent intent = new Intent();
intent.setAction(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
BuildConfig.APPLICATION_ID, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
})
.show();
}
}
}
/** * Receiver for broadcasts sent by {@link LocationService}. */ private class MyReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
Location location = intent.getParcelableExtra(LocationService.EXTRA_LOCATION);
if (location != null) {
Toast.makeText(MainActivity.this, Utils.getLocationText(location),
Toast.LENGTH_SHORT).show();
}
}
}
@Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
// Update the buttons state depending on whether location updates are being requested. if (s.equals(Utils.KEY_REQUESTING_LOCATION_UPDATES)) {
setButtonsState(sharedPreferences.getBoolean(Utils.KEY_REQUESTING_LOCATION_UPDATES,
false));
}
}
private void setButtonsState(boolean requestingLocationUpdates) {
if (requestingLocationUpdates) {
mRequestLocationUpdatesButton.setEnabled(false);
mRemoveLocationUpdatesButton.setEnabled(true);
} else {
mRequestLocationUpdatesButton.setEnabled(true);
mRemoveLocationUpdatesButton.setEnabled(false);
}
}
}
===============end acticity ======
3. Crearte Xml
activity_main
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" android:id="@+id/activity_main" tools:context=".MainActivity">
<Button android:id="@+id/request_location_updates_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/request_location_updates" />
<Button android:id="@+id/remove_location_updates_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/remove_location_updates" />
</LinearLayout>
=============end xml =================================
4. careat service calss LocationService
import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
public class LocationService extends Service {
private static final String PACKAGE_NAME =
"com.nagraj.autocompletedemo";
private static final String TAG = LocationService.class.getSimpleName();
/** * The name of the channel for notifications. */ private static final String CHANNEL_ID = "channel_01";
static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";
static final String EXTRA_LOCATION = PACKAGE_NAME + ".location";
private static final String EXTRA_STARTED_FROM_NOTIFICATION = PACKAGE_NAME +
".started_from_notification";
private final IBinder mBinder = new LocalBinder();
/** * The desired interval for location updates. Inexact. Updates may be more or less frequent. */ private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
/** * The fastest rate for active location updates. Updates will never be more frequent * than this value. */ private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
/** * The identifier for the notification displayed for the foreground service. */ private static final int NOTIFICATION_ID = 12345678;
/** * Used to check whether the bound activity has really gone away and not unbound as part of an * orientation change. We create a foreground service notification only if the former takes * place. */ private boolean mChangingConfiguration = false;
private NotificationManager mNotificationManager;
/** * Contains parameters used by {@link com.google.android.gms.location.FusedLocationProviderApi}. */ private LocationRequest mLocationRequest;
/** * Provides access to the Fused Location Provider API. */ private FusedLocationProviderClient mFusedLocationClient;
/** * Callback for changes in location. */ private LocationCallback mLocationCallback;
private Handler mServiceHandler;
/** * The current location. */ private Location mLocation;
public LocationService() {
}
@Override public void onCreate() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
@Override public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
onNewLocation(locationResult.getLastLocation());
}
};
createLocationRequest();
getLastLocation();
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mServiceHandler = new Handler(handlerThread.getLooper());
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Android O requires a Notification Channel. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.app_name);
// Create the channel for the notification NotificationChannel mChannel =
new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT);
// Set the Notification Channel for the Notification Manager. mNotificationManager.createNotificationChannel(mChannel);
}
}
@Override public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service started");
boolean startedFromNotification = intent.getBooleanExtra(EXTRA_STARTED_FROM_NOTIFICATION,
false);
// We got here because the user decided to remove location updates from the notification. if (startedFromNotification) {
removeLocationUpdates();
stopSelf();
}
// Tells the system to not try to recreate the service after it has been killed. return START_NOT_STICKY;
}
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mChangingConfiguration = true;
}
@Override public IBinder onBind(Intent intent) {
// Called when a client (MainActivity in case of this sample) comes to the foreground // and binds with this service. The service should cease to be a foreground service // when that happens. Log.i(TAG, "in onBind()");
stopForeground(true);
mChangingConfiguration = false;
return mBinder;
}
@Override public void onRebind(Intent intent) {
// Called when a client (MainActivity in case of this sample) returns to the foreground // and binds once again with this service. The service should cease to be a foreground // service when that happens. Log.i(TAG, "in onRebind()");
stopForeground(true);
mChangingConfiguration = false;
super.onRebind(intent);
}
@Override public boolean onUnbind(Intent intent) {
Log.i(TAG, "Last client unbound from service");
// Called when the last client (MainActivity in case of this sample) unbinds from this // service. If this method is called due to a configuration change in MainActivity, we // do nothing. Otherwise, we make this service a foreground service. if (!mChangingConfiguration && Utils.requestingLocationUpdates(this)) {
Log.i(TAG, "Starting foreground service");
startForeground(NOTIFICATION_ID, getNotification());
}
return true; // Ensures onRebind() is called when a client re-binds. }
@Override public void onDestroy() {
mServiceHandler.removeCallbacksAndMessages(null);
}
/** * Makes a request for location updates. Note that in this sample we merely log the * {@link SecurityException}. */ public void requestLocationUpdates() {
Log.i(TAG, "Requesting location updates");
Utils.setRequestingLocationUpdates(this, true);
startService(new Intent(getApplicationContext(), LocationService.class));
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
Utils.setRequestingLocationUpdates(this, false);
Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
}
}
/** * Removes location updates. Note that in this sample we merely log the * {@link SecurityException}. */ public void removeLocationUpdates() {
Log.i(TAG, "Removing location updates");
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
Utils.setRequestingLocationUpdates(this, false);
stopSelf();
} catch (SecurityException unlikely) {
Utils.setRequestingLocationUpdates(this, true);
Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
}
}
/** * Returns the {@link NotificationCompat} used as part of the foreground service. */ private Notification getNotification() {
Intent intent = new Intent(this, LocationService.class);
CharSequence text = Utils.getLocationText(mLocation);
// Extra to help us figure out if we arrived in onStartCommand via the notification or not. intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
// The PendingIntent that leads to a call to onStartCommand() in this service. PendingIntent servicePendingIntent = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// The PendingIntent to launch activity. PendingIntent activityPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.addAction(R.mipmap.ic_launcher, getString(R.string.launch_activity),
activityPendingIntent)
.addAction(R.mipmap.ic_launcher, getString(R.string.remove_location_updates),
servicePendingIntent)
.setContentText(text)
.setContentTitle(Utils.getLocationTitle(this))
.setOngoing(true)
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker(text)
.setWhen(System.currentTimeMillis());
// Set the Channel ID for Android O. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID); // Channel ID }
return builder.build();
}
private void getLastLocation() {
try {
mFusedLocationClient.getLastLocation()
.addOnCompleteListener(new OnCompleteListener<Location>() {
@Override public void onComplete(@NonNull Task<Location> task) {
if (task.isSuccessful() && task.getResult() != null) {
mLocation = task.getResult();
} else {
Log.w(TAG, "Failed to get location.");
}
}
});
} catch (SecurityException unlikely) {
Log.e(TAG, "Lost location permission." + unlikely);
}
}
private void onNewLocation(Location location) {
Log.i(TAG, "New location: " + location);
mLocation = location;
// Notify anyone listening for broadcasts about the new location. Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// Update notification content if running as a foreground service. if (serviceIsRunningInForeground(this)) {
mNotificationManager.notify(NOTIFICATION_ID, getNotification());
}
}
/** * Sets the location request parameters. */ private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/** * Class used for the client Binder. Since this service runs in the same process as its * clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder {
LocationService getService() {
return LocationService.this;
}
}
/** * Returns true if this is a foreground service. * * @param context The {@link Context}. */ public boolean serviceIsRunningInForeground(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
Integer.MAX_VALUE)) {
if (getClass().getName().equals(service.service.getClassName())) {
if (service.foreground) {
return true;
}
}
}
return false;
}
}
====================end service =====================
5. add AndroidManifest file
I. Permission
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- Required for foreground services on P+. --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
II. Service
<application
<!-- Foreground services in Q+ require type. --> <service android:name=".LocationService" android:enabled="true" android:exported="true" android:foregroundServiceType="location" />
</application>
======================end manifest =======
6. create Utils class
import android.content.Context;
import android.location.Location;
import android.preference.PreferenceManager;
import java.text.DateFormat;
import java.util.Date;
public class Utils {
static final String KEY_REQUESTING_LOCATION_UPDATES = "requesting_locaction_updates";
/** * Returns true if requesting location updates, otherwise returns false. * * @param context The {@link Context}. */ static boolean requestingLocationUpdates(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(KEY_REQUESTING_LOCATION_UPDATES, false);
}
/** * Stores the location updates state in SharedPreferences. * @param requestingLocationUpdates The location updates state. */ static void setRequestingLocationUpdates(Context context, boolean requestingLocationUpdates) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putBoolean(KEY_REQUESTING_LOCATION_UPDATES, requestingLocationUpdates)
.apply();
}
/** * Returns the {@code location} object as a human readable string. * @param location The {@link Location}. */ static String getLocationText(Location location) {
return location == null ? "Unknown location" :
"(" + location.getLatitude() + ", " + location.getLongitude() + ")";
}
static String getLocationTitle(Context context) {
return context.getString(R.string.location_updated,
DateFormat.getDateTimeInstance().format(new Date()));
}
}
=================end utils =======
7. String file
<string name="launch_activity">Launch activity</string>
<string name="location_unknown">Location unknown</string>
<string name="location_updates_label">Location Updates</string>
<string name="permission_rationale">Location permission is needed for core functionality</string>
<string name="permission_denied_explanation">Permission was denied, but is needed for core
functionality.</string>
<string name="settings">Settings</string>
<string name="ok">OK</string>
<string name="request_location_updates">Request location updates</string>
<string name="remove_location_updates">Remove location updates</string>
<string name="location_updated">Location Updated: %1$s</string>
=====================end string =====
=============================
1.
MainActivity
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import com.google.android.material.snackbar.Snackbar;
public class MainActivity extends AppCompatActivity {
String TAG = MainActivity.class.getSimpleName();
// Used in checking for runtime permissions. private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
// A reference to the service used to get location updates. private LocationService mService = null;
// Tracks the bound state of the service. private boolean mBound = false;
// Monitors the state of the connection to the service. private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override public void onServiceConnected(ComponentName name, IBinder service) {
LocationService.LocalBinder binder = (LocationService.LocalBinder) service;
mService = binder.getService();
mBound = true;
mService.requestLocationUpdates();
}
@Override public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
mService.removeLocationUpdates();
}
};
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override protected void onStart() {
super.onStart();
// Bind to the service. If the service is in foreground mode, this signals to the service // that since this activity is in the foreground, the service can exit foreground mode. bindService(new Intent(this, LocationService.class), mServiceConnection,
Context.BIND_AUTO_CREATE);
// Check that the user hasn't revoked permissions by going to Settings. if (!checkPermissions()) {
requestPermissions();
}
}
@Override protected void onResume() {
super.onResume();
}
@Override protected void onStop() {
super.onStop();
if (mBound) {
// Unbind from the service. This signals to the service that this activity is no longer // in the foreground, and the service can respond by promoting itself to a foreground // service. unbindService(mServiceConnection);
mBound = false;
}
}
@Override protected void onDestroy() {
super.onDestroy();
mService.removeLocationUpdates();
if (mBound) {
// Unbind from the service. This signals to the service that this activity is no longer // in the foreground, and the service can respond by promoting itself to a foreground // service. unbindService(mServiceConnection);
mBound = false;
}
}
/** * Returns the current state of the permissions needed. */ private boolean checkPermissions() {
return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION);
}
private void requestPermissions() {
boolean shouldProvideRationale =
ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION);
// Provide an additional rationale to the user. This would happen if the user denied the // request previously, but didn't check the "Don't ask again" checkbox. if (shouldProvideRationale) {
Log.i(TAG, "Displaying permission rationale to provide additional context.");
Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
@Override public void onClick(View view) {
// Request permission ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
}
})
.show();
} else {
Log.i(TAG, "Requesting permission");
// Request permission. It's possible this can be auto answered if device policy // sets the permission in a given state or the user denied the permission // previously and checked "Never ask again". ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERMISSIONS_REQUEST_CODE);
}
}
/** * Callback received when a permissions request has been completed. */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
Log.i(TAG, "onRequestPermissionResult");
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
if (grantResults.length <= 0) {
// If user interaction was interrupted, the permission request is cancelled and you // receive empty arrays. Log.i(TAG, "User interaction was cancelled.");
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission was granted. mService.requestLocationUpdates();
} else {
// Permission denied. Snackbar.make(
findViewById(R.id.activity_main),
R.string.permission_denied_explanation,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.settings, new View.OnClickListener() {
@Override public void onClick(View view) {
// Build intent that displays the App settings screen. Intent intent = new Intent();
intent.setAction(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package",
BuildConfig.APPLICATION_ID, null);
intent.setData(uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
})
.show();
}
}
}
}
=================================
2.
LocationService
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import java.text.DateFormat;
import java.util.Date;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
public class LocationService extends Service {
private static final String PACKAGE_NAME =
"om.nagraj.ml";
private static final String TAG = LocationService.class.getSimpleName();
/** * The name of the channel for notifications. */ private static final String CHANNEL_ID = "channel_01";
static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";
static final String EXTRA_LOCATION = PACKAGE_NAME + ".location";
private static final String EXTRA_STARTED_FROM_NOTIFICATION = PACKAGE_NAME +
".started_from_notification";
private final IBinder mBinder = new LocalBinder();
/** * The desired interval for location updates. Inexact. Updates may be more or less frequent. */ private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
/** * The fastest rate for active location updates. Updates will never be more frequent * than this value. */ private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
/** * The identifier for the notification displayed for the foreground service. */ private static final int NOTIFICATION_ID = 12345678;
/** * Used to check whether the bound activity has really gone away and not unbound as part of an * orientation change. We create a foreground service notification only if the former takes * place. */ private boolean mChangingConfiguration = false;
private NotificationManager mNotificationManager;
/** * Contains parameters used by {@link com.google.android.gms.location.FusedLocationProviderApi}. */ private LocationRequest mLocationRequest;
/** * Provides access to the Fused Location Provider API. */ private FusedLocationProviderClient mFusedLocationClient;
/** * Callback for changes in location. */ private LocationCallback mLocationCallback;
private Handler mServiceHandler;
/** * The current location. */ private Location mLocation;
public LocationService() {
}
@Override public void onCreate() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mLocationCallback = new LocationCallback() {
@Override public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
onNewLocation(locationResult.getLastLocation());
}
};
createLocationRequest();
getLastLocation();
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mServiceHandler = new Handler(handlerThread.getLooper());
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Android O requires a Notification Channel. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.app_name);
// Create the channel for the notification NotificationChannel mChannel =
new NotificationChannel(CHANNEL_ID, name, NotificationManager.IMPORTANCE_DEFAULT);
// Set the Notification Channel for the Notification Manager. mNotificationManager.createNotificationChannel(mChannel);
}
}
@Override public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service started");
boolean startedFromNotification = intent.getBooleanExtra(EXTRA_STARTED_FROM_NOTIFICATION,
false);
// We got here because the user decided to remove location updates from the notification. if (startedFromNotification) {
removeLocationUpdates();
stopSelf();
}
// Tells the system to not try to recreate the service after it has been killed. return START_NOT_STICKY;
}
@Override public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mChangingConfiguration = true;
}
@Override public IBinder onBind(Intent intent) {
// Called when a client (MainActivity in case of this sample) comes to the foreground // and binds with this service. The service should cease to be a foreground service // when that happens. Log.i(TAG, "in onBind()");
stopForeground(true);
mChangingConfiguration = false;
return mBinder;
}
@Override public void onRebind(Intent intent) {
// Called when a client (MainActivity in case of this sample) returns to the foreground // and binds once again with this service. The service should cease to be a foreground // service when that happens. Log.i(TAG, "in onRebind()");
stopForeground(true);
mChangingConfiguration = false;
super.onRebind(intent);
}
@Override public boolean onUnbind(Intent intent) {
Log.i(TAG, "Last client unbound from service");
// Called when the last client (MainActivity in case of this sample) unbinds from this // service. If this method is called due to a configuration change in MainActivity, we // do nothing. Otherwise, we make this service a foreground service.
if (!mChangingConfiguration) {
Log.i(TAG, "Starting foreground service");
startForeground(NOTIFICATION_ID, getNotification());
//startForeground(NOTIFICATION_ID, null,getServiceType()); }
return true; // Ensures onRebind() is called when a client re-binds. }
@Override public void onDestroy() {
mServiceHandler.removeCallbacksAndMessages(null);
}
/** * Makes a request for location updates. Note that in this sample we merely log the * {@link SecurityException}. */ public void requestLocationUpdates() {
Log.i(TAG, "Requesting location updates");
//Utils.setRequestingLocationUpdates(this, true); startService(new Intent(getApplicationContext(), LocationService.class));
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
} catch (SecurityException unlikely) {
// Utils.setRequestingLocationUpdates(this, false); Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
}
}
/** * Removes location updates. Note that in this sample we merely log the * {@link SecurityException}. */ public void removeLocationUpdates() {
Log.i(TAG, "Removing location updates");
try {
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
//Utils.setRequestingLocationUpdates(this, false); stopSelf();
} catch (SecurityException unlikely) {
// Utils.setRequestingLocationUpdates(this, true); Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
}
}
/** * Returns the {@link NotificationCompat} used as part of the foreground service. */ private Notification getNotification() {
Intent intent = new Intent(this, LocationService.class);
String text = String.valueOf(mLocation.getLatitude() + mLocation.getLongitude());
// Extra to help us figure out if we arrived in onStartCommand via the notification or not. intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
// The PendingIntent that leads to a call to onStartCommand() in this service. PendingIntent servicePendingIntent = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// The PendingIntent to launch activity. PendingIntent activityPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.addAction(R.mipmap.ic_launcher, getString(R.string.launch_activity),
activityPendingIntent)
.addAction(R.mipmap.ic_launcher, getString(R.string.remove_location_updates),
servicePendingIntent)
.setContentText(text)
.setContentTitle(getString(R.string.location_updated,DateFormat.getDateTimeInstance().format(new Date())))
.setOngoing(true)
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(R.mipmap.ic_launcher)
.setTicker(text)
.setWhen(System.currentTimeMillis());
// Set the Channel ID for Android O. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID); // Channel ID }
return builder.build();
}
private void getLastLocation() {
try {
mFusedLocationClient.getLastLocation()
.addOnCompleteListener(new OnCompleteListener<Location>() {
@Override public void onComplete(@NonNull Task<Location> task) {
if (task.isSuccessful() && task.getResult() != null) {
mLocation = task.getResult();
} else {
Log.w(TAG, "Failed to get location.");
}
}
});
} catch (SecurityException unlikely) {
Log.e(TAG, "Lost location permission." + unlikely);
}
}
private void onNewLocation(Location location) {
Log.i(TAG, "New location: " + location);
mLocation = location;
//Notify anyone listening for broadcasts about the new location. Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
/** * Sets the location request parameters. */ private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/** * Class used for the client Binder. Since this service runs in the same process as its * clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder {
LocationService getService() {
return LocationService.this;
}
}
protected int getServiceType() {
return FOREGROUND_SERVICE_TYPE_MANIFEST;
}
}
==============*****================
Thanks all