How to get current location (latitude, longitude) with GPS in Android Android 17.04.2017

How to get current location (latitude, longitude) with GPS in Android

Android Location API can be used to track your mobile current location and show in the app. In this tutorial, you will learn how to get your current location in Android using GPS.

There are two ways to get a users location in our application:

  • android.location.LocationListener. This is a part of the Android API.
  • com.google.android.gms.location.LocationListener. This is present in the Google Play Services API.

Google officially recommends using Google Play Location Service APIs. Android Location Services API is still used to develop location-based apps for devices that don’t support Google Play Services.

LocationListener from android.location

There are three main componets of Location API:

  • Location class gives geographic location. It contains latitude and longitude etc.
  • LocationManager provides access to the system location services.
  • LocationListener used for receiving notifications from the LocationManager when the location has changed.

The Location object represents a geographic location which can consist of a latitude, longitude, time stamp, and other information such as bearing, altitude and velocity. There are following important methods which you can use with Location object to get location specific information.

  • distanceTo(Location dest). Returns the approximate distance in meters between this location and the given location.
  • getAccuracy(). Get the estimated accuracy of this location, in meters.
  • getAltitude(). Get the altitude if available, in meters above sea level.
  • getLatitude(). Get the latitude, in degrees.
  • getLongitude(). Get the longitude, in degrees.
  • getBearing(). Get the bearing, in degrees.
  • getSpeed(). Get the speed if it is available, in meters/second over ground.
  • setLatitude(double latitude). Set the latitude, in degrees.
  • setLongitude(double longitude). Set the longitude, in degrees.

LocationManger class provides access to the system location services. These services allow applications to obtain periodic updates of the device’s geographical location, or to fire an application-specified Intent when the device enters the proximity of a given geographical location.

The LocationListener class needs to implement the following methods.

  • onLocationChanged(Location location). Called when the location has changed.
  • onProviderDisabled(String provider). Called when the provider is disabled by the user.
  • onProviderEnabled(String provider). Called when the provider is enabled by the user.
  • onStatusChanged(String provider, int status, Bundle extras). Called when the provider status changes.

The LocationManager has two means of acquiring location data:

  • LocationManager.GPS_PROVIDER. Determines location using satellites. Depending on the conditions, this provider may take a while to return a location fix.
  • LocationManager.NETWORK_PROVIDER. Determines location based on the availability of nearby cell towers and WiFi access points. This is faster than GPS_PROVIDER.

Next, we’ll add the LocationListener interface to our Activity to receive periodic location updates via GPS Providers or Network Providers.

To run our GPS Location Manager application, we need to provide the permissions given below. Add the permission on the AndroidManifest.xml file.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

The activity_main.xml layout is defined below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:text="Latitude:"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tvLatitude"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:text="Longitude:"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tvLongitude"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:text="Time of request:"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tvTime"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

The MainActivity.java class is defined below.

import android.Manifest;

public class SecondActivity extends AppCompatActivity implements LocationListener {
    final String TAG = "GPS";
    private final static int ALL_PERMISSIONS_RESULT = 101;
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;
    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;

    TextView tvLatitude, tvLongitude, tvTime;
    LocationManager locationManager;
    Location loc;
    ArrayList<String> permissions = new ArrayList<>();
    ArrayList<String> permissionsToRequest;
    ArrayList<String> permissionsRejected = new ArrayList<>();
    boolean isGPS = false;
    boolean isNetwork = false;
    boolean canGetLocation = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        tvLatitude = (TextView) findViewById(R.id.tvLatitude);
        tvLongitude = (TextView) findViewById(R.id.tvLongitude);
        tvTime = (TextView) findViewById(R.id.tvTime);

        locationManager = (LocationManager) getSystemService(Service.LOCATION_SERVICE);
        isGPS = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        isNetwork = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
        permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
        permissionsToRequest = findUnAskedPermissions(permissions);

        if (!isGPS && !isNetwork) {
            Log.d(TAG, "Connection off");
            showSettingsAlert();
            getLastLocation();
        } else {
            Log.d(TAG, "Connection on");
            // check permissions
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (permissionsToRequest.size() > 0) {
                    requestPermissions(permissionsToRequest.toArray(new String[permissionsToRequest.size()]),
                            ALL_PERMISSIONS_RESULT);
                    Log.d(TAG, "Permission requests");
                    canGetLocation = false;
                }
            }

            // get location
            getLocation();
        }
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.d(TAG, "onLocationChanged");
        updateUI(location);
    }

    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {}

    @Override
    public void onProviderEnabled(String s) {
        getLocation();
    }

    @Override
    public void onProviderDisabled(String s) {
        if (locationManager != null) {
            locationManager.removeUpdates(this);
        }
    }

    private void getLocation() {
        try {
            if (canGetLocation) {
                Log.d(TAG, "Can get location");
                if (isGPS) {
                    // from GPS
                    Log.d(TAG, "GPS on");
                    locationManager.requestLocationUpdates(
                            LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        if (loc != null)
                            updateUI(loc);
                    }
                } else if (isNetwork) {
                    // from Network Provider
                    Log.d(TAG, "NETWORK_PROVIDER on");
                    locationManager.requestLocationUpdates(
                            LocationManager.NETWORK_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                        if (loc != null)
                            updateUI(loc);
                    }
                } else {
                    loc.setLatitude(0);
                    loc.setLongitude(0);
                    updateUI(loc);
                }
            } else {
                Log.d(TAG, "Can't get location");
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private void getLastLocation() {
        try {
            Criteria criteria = new Criteria();
            String provider = locationManager.getBestProvider(criteria, false);
            Location location = locationManager.getLastKnownLocation(provider);
            Log.d(TAG, provider);
            Log.d(TAG, location == null ? "NO LastLocation" : location.toString());
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private ArrayList findUnAskedPermissions(ArrayList<String> wanted) {
        ArrayList result = new ArrayList();

        for (String perm : wanted) {
            if (!hasPermission(perm)) {
                result.add(perm);
            }
        }

        return result;
    }

    private boolean hasPermission(String permission) {
        if (canAskPermission()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                return (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);
            }
        }
        return true;
    }

    private boolean canAskPermission() {
        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
    }

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case ALL_PERMISSIONS_RESULT:
                Log.d(TAG, "onRequestPermissionsResult");
                for (String perms : permissionsToRequest) {
                    if (!hasPermission(perms)) {
                        permissionsRejected.add(perms);
                    }
                }

                if (permissionsRejected.size() > 0) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        if (shouldShowRequestPermissionRationale(permissionsRejected.get(0))) {
                            showMessageOKCancel("These permissions are mandatory for the 
                                  application. Please allow access.",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                        requestPermissions(permissionsRejected.toArray(
                                                new String[permissionsRejected.size()]), ALL_PERMISSIONS_RESULT);
                                    }
                                }
                            });
                            return;
                        }
                    }
                } else {
                    Log.d(TAG, "No rejected permissions.");
                    canGetLocation = true;
                    getLocation();
                }
                break;
        }
    }

    public void showSettingsAlert() {
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
        alertDialog.setTitle("GPS is not Enabled!");
        alertDialog.setMessage("Do you want to turn on GPS?");
        alertDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(intent);
            }
        });

        alertDialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.cancel();
            }
        });

        alertDialog.show();
    }

    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(SecondActivity.this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }

    private void updateUI(Location loc) {
        Log.d(TAG, "updateUI");
        tvLatitude.setText(Double.toString(loc.getLatitude()));
        tvLongitude.setText(Double.toString(loc.getLongitude()));
        tvTime.setText(DateFormat.getTimeInstance().format(loc.getTime()));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (locationManager != null) {
            locationManager.removeUpdates(this);
        }
    }
}

In the above code, we’re implementing runtime permissions that are used in Android 6.0+ devices. We’ve added the ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION permissions in the AndroidManifest.xml file.

Updating of location begin when Activity start. isProviderEnabled(String provider)method is called upon the locationManager object and is used to check whether GPS/Network Provider is enabled or not. If the Providers aren’t enabled we’re calling the method showSettingsAlert() that shows a prompt to enable GPS.

Method requestLocationUpdates() of the LocationManager class is used to register the service to be notified periodically by the named provider.

The parameters of this function are as follows:

  • provider is the name of the provider with which we would like to regiser.
  • minTime is minimum time interval between location updates (in milliseconds).
  • minDistance is minimum distance between location updates (in meters).
  • listener is a LocationListener whose onLocationChanged(Location) method will be called for each location update.

onLocationChanged is invoked periodically based upon the minTime and minDistance, whichever comes first.

onProviderDisabled will notify the app that GPS has been disabled on the device. Here we stop listening for updates when this happens.

onProviderEnabled lets us know that GPS is back and we can start listening again.

To stop location updates removeUpdates method is called on the LocationManager instance.

Result

android_location.png

LocationListener from gms.location

The Google Location Services API, part of Google Play Services, provides a more powerful, high-level framework that automatically handles location providers, user movement, and location accuracy. It also handles location update scheduling based on power consumption parameters you provide. In most cases, you’ll get better battery performance, as well as more appropriate accuracy, by using the Location Services API.

Android allows applications to obtain location data from multiple sources. High-accuracy (and also high-power-drain) fixes come from on on-board GPS. Lower-accuracy data is obtained from network sources, such as cellular towers and Wi-Fi hotspots. Google's fused location provider gets its name from "fusing" these multiple sources together to provide developers with the best result at all times. Location requests are made with higher-level criteria, and the device does the work of determining which hardware interfaces should be involved:

  • PRIORITY_BALANCED_POWER_ACCURACY. Provides a mix of GPS and network sources to get good accuracy with lower power and quicker fixes. Use this setting to request location precision to within a city block, which is an accuracy of approximately 100 meters. This is considered a coarse level of accuracy, and is likely to consume less power.
  • PRIORITY_HIGH_ACCURACY. Requires a final fix to come from GPS (most accurate), though initial fixes may come from elsewhere. This option also requires the most power as the GPS is typically on all the time. Use this setting to request the most precise location possible. With this setting, the location services are more likely to use GPS to determine the location.
  • PRIORITY_LOW_POWER. Provides the quickest fixes—but without GPS assistance, the accuracy is generally not better than "city" level. Use this setting to request city-level precision, which is an accuracy of approximately 10 kilometers. This is considered a coarse level of accuracy, and is likely to consume less power.
  • PRIORITY_NO_POWER. Enables your application to be a passive observer. Updates will be delivered only when another application triggers them. Use this setting if you need negligible impact on power consumption, but want to receive location updates when available. With this setting, your app does not trigger any location updates, but receives locations triggered by other apps.

The priority of PRIORITY_HIGH_ACCURACY, combined with the ACCESS_FINE_LOCATION permission setting that you’ve defined in the app manifest, and a fast update interval of 5000 milliseconds (5 seconds), causes the fused location provider to return location updates that are accurate to within a few feet. This approach is appropriate for mapping apps that display the location in real time.

The location services in this example are distributed as part of the Google Play Services library, they are not part of the native SDK at any platform level.

The main enhanced point is that Google Play Location Service provides Fused Location Provider. Main benefits of Fused Location Provider are:

  1. It provides simple and easy to use Location APIs.
  2. Provides high accuracy over other options.
  3. Utilizes low power by choosing the most efficient way to access the location.

With respect to Fused Location Provider, we can broadly classify the API usage in three use cases.

  • getLastLocation(GoogleApiClient) this API should be used when there is no need for continuous access to location from an application. Like one shot access or get user location based on some action. This is the simplified way to get the device location and also may not provide high accuracy.
  • requestLocationUpdates(GoogleApiClient,LocationRequest, LocationListener) this API should be used when there a need for continuous location updates and the location is accessed when the application is active in foreground.
  • requestLocationUpdates (GoogleApiClient, LocationRequest, PendingIntent) this API is used to receive location updates in the background even when the application is not active. So the difference is PendingIntent.

Google Play Services is required. If you are using Android Studio and Gradle, you should have the following dependencies added in build.gradle file

dependencies {
    ...
    // for emulator
    compile 'com.google.android.gms:play-services:8+'
    compile 'com.google.android.gms:play-services-location:8+'

    // for real device
    //compile 'com.google.android.gms:play-services:10.2.1'
}

First of all, verify play services is active and up to date

int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this);
switch (resultCode) {
    case ConnectionResult.SUCCESS:
        Log.d(TAG, "Google Play Services is ready to go!");
        break;
    default:
        showPlayServicesError(resultCode);
        return;
}

/*
* When Play Services is missing or at the wrong version, the client
* library will assist with a dialog to help the user update.
*/
private void showPlayServicesError(int errorCode) {
    GoogleApiAvailability.getInstance().showErrorDialogFragment(this, errorCode, 10,
        new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialogInterface) {
                finish();
            }
        });
}

Also specify the following required permission in your manifest.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

When using location services in an application, keep in mind that android.permission.ACCESS_COARSE_LOCATION or android.permission.ACCESS_FINE_LOCATION must be declared in the application manifest. If you declare android.permission.ACCESS_FINE_LOCATION, you do not need both because it includes coarse permissions as well.

Now you can access the last known location. The Fused Location Provider provides a new simple API. The following is an example activity which uses it.

The following interfaces should be implemented in Activity (for example) to get the location update.

  • GoogleApiClient.ConnectionCallbacks provides callbacks that are triggered when the client is connected (onConnected()) or temporarily disconnected (onConnectionSuspended()) from the service.
  • GoogleApiClient.OnConnectionFailedListener provides a callback method (onConnectionFailed()) that is triggered when an attempt to connect the client to the service results in a failure.
  • LocationListener defines the onLocationChanged() which is called when a user’s location changes. This method is only called if the LocationListener has been registered.

You can find out, if a GPS is enabled via the isProviderEnabled() method of LocationManager. If its not enabled you can send the user to the settings via an Intent with the Settings.ACTION_LOCATION_SOURCE_SETTINGS action for the android.provider.Settings class.

LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);

if (!enabled) {
  Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        startActivity(intent);
}

Fused Location Provider requires the GoogleApiClient instance to get the Location and it can be obtained as below.

gac = new GoogleApiClient.Builder(locationActivity)
    .addApi(LocationServices.API)
    .addConnectionCallbacks(this)
    .addOnConnectionFailedListener(this)
    .build();

Some explanation to code above:

  • Instantiating the GoogleApiClient should be done in onCreate of the application Activity.
  • gac.connect() should be done in onStart and gac.disconnect() in onStop.
  • When the GoogleApiClient is connected successfully, onConnected(Bundle) callback will be called. There we should register with LocationListener for location updates as LocationServices.FusedLocationApi.requestLocationUpdates( gac, locationRequest, this);

LocationRequest objects are used to request a quality of service for location updates from the FusedLocationProviderApi. For example, if your application wants high accuracy location it should create a location request with setPriority(int) set to PRIORITY_HIGH_ACCURACY and setInterval(long) to 5 seconds. This would be appropriate for mapping applications that are showing your location in real-time.

There are two options to set interval to receive updates:

  • setInterval() specifies the rate at which your app will like to receive updates. This method sets the rate in milliseconds at which your app prefers to receive location updates. Note that the location updates may be faster than this rate if another app is receiving updates at a faster rate, or slower than this rate, or there may be no updates at all.
  • setFastestInterval() specifies the fastest rate at which the app can handle updates. Setting the fastestInterval rate places a limit on how fast updates will be sent to your app. This method sets the fastest rate in milliseconds at which your app can handle location updates. You need to set this rate because other apps also affect the rate at which updates are sent. The Google Play services location APIs send out updates at the fastest rate that any app has requested with setInterval(). If this rate is faster than your app can handle, you may encounter problems with UI flicker or data overflow. To prevent this, call setFastestInterval() to set an upper limit to the update rate.
private static final int UPDATE_INTERVAL = 15 * 1000;
private static final int FASTEST_UPDATE_INTERVAL = 2 * 1000;

locationRequest = LocationRequest.create()
    //Set the required accuracy level
    .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
    //Set the desired (inexact) frequency of location updates
    .setInterval(UPDATE_INTERVAL)
    //Throttle the max rate of update requests
    .setFastestInterval(FASTEST_UPDATE_INTERVAL);

We construct a LocationRequest containing all the criteria we want applied to the updates received. We instruct the service to return only high-accuracy results, at an interval of 15 seconds. This interval is inexact, meaning Android will deliver the updates roughly every 15 seconds—maybe more, maybe less. The only guarantee is that you will receive at most one update in that interval. In order to set an upper bound on this interval, we also set the fastest interval to 2 seconds. This throttles the updates to ensure that we never receive any two updates faster than 2 seconds apart.

If you are receiving updates in a service or other background operation, Google recommends that the minimum time interval should be no less than 60,000 (60 seconds).

The activity_main.xml layout is defined below.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:text="Latitude:"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tvLatitude"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:text="Longitude:"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tvLongitude"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:text="Time of request:"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/tvTime"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

The MainActivity.java class is defined below.

public class MainActivity extends AppCompatActivity implements LocationListener, 
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    final String TAG = "GPS";
    private long UPDATE_INTERVAL = 2 * 1000;  /* 10 secs */
    private long FASTEST_INTERVAL = 2000; /* 2 sec */
    static final int MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;

    GoogleApiClient gac;
    LocationRequest locationRequest;
    TextView tvLatitude, tvLongitude, tvTime;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvLatitude = (TextView) findViewById(R.id.tvLatitude);
        tvLongitude = (TextView) findViewById(R.id.tvLongitude);
        tvTime = (TextView) findViewById(R.id.tvTime);

        isGooglePlayServicesAvailable();

        if(!isLocationEnabled())
            showAlert();

        locationRequest = new LocationRequest();
        locationRequest.setInterval(UPDATE_INTERVAL);
        locationRequest.setFastestInterval(FASTEST_INTERVAL);
        locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        gac = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
    }

    @Override
    protected void onStart() {
        gac.connect();
        super.onStart();
    }

    @Override
    protected void onStop() {
        gac.disconnect();
        super.onStop();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location != null) {
            updateUI(location);
        }
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED
        && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
        != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this,
            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
            MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

            return;
        }
        Log.d(TAG, "onConnected");

        Location ll = LocationServices.FusedLocationApi.getLastLocation(gac);
        Log.d(TAG, "LastLocation: " + (ll == null ? "NO LastLocation" : ll.toString()));

        LocationServices.FusedLocationApi.requestLocationUpdates(gac, locationRequest, this);
    }

    @Override
    public void onRequestPermissionsResult(
        int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(MainActivity.this, "Permission was granted!", Toast.LENGTH_LONG).show();

                    try{
                        LocationServices.FusedLocationApi.requestLocationUpdates(
                        gac, locationRequest, this);
                    } catch (SecurityException e) {
                        Toast.makeText(MainActivity.this, "SecurityException:\n" + e.toString(), 
                            Toast.LENGTH_LONG).show();
                    }
                } else {
                    Toast.makeText(MainActivity.this, "Permission denied!", Toast.LENGTH_LONG).show();
                }
                return;
            }
        }
    }

    @Override
    public void onConnectionSuspended(int i) {}

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        Toast.makeText(MainActivity.this, "onConnectionFailed: \n" + connectionResult.toString(),
        Toast.LENGTH_LONG).show();
        Log.d("DDD", connectionResult.toString());
    }

    private void updateUI(Location loc) {
        Log.d(TAG, "updateUI");
        tvLatitude.setText(Double.toString(loc.getLatitude()));
        tvLongitude.setText(Double.toString(loc.getLongitude()));
        tvTime.setText(DateFormat.getTimeInstance().format(loc.getTime()));
    }

    private boolean isLocationEnabled() {
        LocationManager locationManager = 
            (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
                locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    }

    private boolean isGooglePlayServicesAvailable() {
        final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
        GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
        int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
        if (resultCode != ConnectionResult.SUCCESS) {
            if (apiAvailability.isUserResolvableError(resultCode)) {
                apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
                        .show();
            } else {
                Log.d(TAG, "This device is not supported.");
                finish();
            }
            return false;
        }
        Log.d(TAG, "This device is supported.");
        return true;
    }

    private void showAlert() {
        final AlertDialog.Builder dialog = new AlertDialog.Builder(this);
        dialog.setTitle("Enable Location")
                .setMessage("Your Locations Settings is set to 'Off'.\nPlease Enable Location to " +
                        "use this app")
                .setPositiveButton("Location Settings", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {

                        Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                        startActivity(myIntent);
                    }
                })
                .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface paramDialogInterface, int paramInt) {

                    }
                });
        dialog.show();
    }
}

We can send location using telnet command. To use this, you need to connect to the device from the command line using the following command:

// telnet localhost [DEVICE_PORT]
telnet localhost 5554

The device port is shown in the virtual device window. The device port is usually equal to 5554.

It is possible that you need to authorize this connection using your auth_token, but the command line shows you where it is located. Navigate to that location and copy the token and type, auth [YOUR_AUTH_TOKEN].

You can now set the location of the device by running the following command:

// geo fix [LATITUDE] [LONGITUDE]
geo fix 49.0933625 33.4391895

Result

android_gms_location.png

Get user last know location

Because it might take time to produce a location estimation, getLastKnownLocation() can be called to retrieve the location last saved for a given provider. The location contains a latitude, longitude, and Coordinated Universal Time (CUT) timestamp.

It's a example to get last know location from both NETWORK_PROVIDER and GPS_PROVIDER, and choice the provider base on its accuracy.

In order to use both NETWORK_PROVIDER and GPS_PROVIDER, only the ACCESS_FINE_LOCATION permission is need, because it includes permission for both providers. (Permission for ACCESS_COARSE_LOCATION includes permission only for NETWORK_PROVIDER).

public class MainActivity extends AppCompatActivity {
    private String TAG = "TAG";

    private Activity activity = MainActivity.this;

    final String gpsLocationProvider = LocationManager.GPS_PROVIDER;
    final String networkLocationProvider = LocationManager.NETWORK_PROVIDER;
    String wantPermission = Manifest.permission.ACCESS_FINE_LOCATION;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LocationManager locationManager = 
             (LocationManager) getSystemService(Context.LOCATION_SERVICE);

        if (checkPermission(wantPermission)) {
            Location lastKnownLocationGps = locationManager.getLastKnownLocation(gpsLocationProvider);
            Location lastKnownLocationNetwork = locationManager.getLastKnownLocation(networkLocationProvider);

            if (lastKnownLocationGps == null) {
                Log.d(TAG, "NO GPS");

                if (lastKnownLocationNetwork == null) {
                    Log.d(TAG, "NO Network");
                    Log.d(TAG, "NO Location!");
                } else {
                    Log.d(TAG, "Network " + lastKnownLocationNetwork.toString());
                    Log.d(TAG, "Location (Network)" + lastKnownLocationNetwork.getLatitude() + ", " + 
                        lastKnownLocationNetwork.getLongitude());
                }
            } else {
                Log.d(TAG, "GPS " + lastKnownLocationGps.toString());

                if (lastKnownLocationNetwork == null) {
                    Log.d(TAG, "NO Network");
                    Log.d(TAG, "Location (GPS) " + lastKnownLocationGps.getLatitude() + ", " + 
                        lastKnownLocationGps.getLongitude());
                    Log.d(TAG, "Time (GPS) " + lastKnownLocationGps.getTime());
                    Log.d(TAG, "Accuracy (GPS) " + lastKnownLocationGps.getAccuracy());
                } else {
                    Log.d(TAG, "Network " + lastKnownLocationNetwork.toString());

                    //Both Location provider have last location decide location base on accuracy
                    if (lastKnownLocationGps.getAccuracy() <= lastKnownLocationNetwork.getAccuracy()) {
                        Log.d(TAG, "Location (GPS) " + lastKnownLocationGps.getLatitude() + ", " + 
                            lastKnownLocationGps.getLongitude());
                    } else {
                        Log.d(TAG, "Location (Network) " + lastKnownLocationNetwork.getLatitude() + ", " + 
                            lastKnownLocationNetwork.getLongitude());
                    }

                }
            }
        }
    }

    private boolean checkPermission(String permission){
        if (Build.VERSION.SDK_INT >= 23) {
            int result = ContextCompat.checkSelfPermission(activity, permission);
            if (result == PackageManager.PERMISSION_GRANTED){
                return true;
            } else {
                return false;
            }
        } else {
            return true;
        }
    }

}

Useful links