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
No comments:
Post a Comment