Android Geolocation GooglePlay Service(Kotlin)

Google Play Service

These days, google play service separates component.(In the past, all features are combined).
And it provides helper functions for Android Development.

Geolocation

Android supports geolocation acquisition by default(Android API).
To support it, we need GPS or Internet(4G, 3G).
GPS is more accurate than Internet.

Permission

To get geolocation, we need additional permission

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

<uses-feature android:name="android.hardware.location.gps" />

First 3 are for GPS.
INTERNET is to use INTERGET geolocation function.
The last is for Android 5 above.

Google Play Service(Google Location and Activity Recognition)

dependencies {
   compile 'com.google.android.gms:play-services:11.0.4'
}

Example

This is a simple example.
Prepare google play API in onCreate.
Connect API in onStart
Start getting geolocation in onResume.

activity_geo_location.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    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_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.atmarkplant.locationlogger.MainActivity">

    <TextView android:id="@+id/geoTextView" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button android:id="@+id/geoGetButton" android:text="Get"
        android:layout_width="match_parent" android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/geoTextView" />

</android.support.constraint.ConstraintLayout>

GooglePlayGeoLocationActivity.kt

class GooglePlayGeoLocationActivity : AppCompatActivity(), GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {


    lateinit var textView : TextView

    var googleApiClient : GoogleApiClient? = null

    lateinit var locationRequest : LocationRequest

    lateinit var locationSettingRequest : LocationSettingsRequest

    var currentLocation : Location? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_geo_location)

        this.textView = findViewById(R.id.geoTextView) as TextView

        val button : Button = findViewById(R.id.geoGetButton) as Button
        button.setOnClickListener {
            try {
                startLocationUpdates()
            }
            catch (e : SecurityException) {
            }
        }

        initGoogleAPIClient()
        createLocationRequest()
        createLocationSettings()
    }

    override fun onStart() {
        super.onStart()
        this.googleApiClient?.connect()
    }

    override fun onResume() {
        super.onResume()

        if (isLocationEnabled(this)) {
            if (googleApiClient != null && googleApiClient!!.isConnected()) {
                startLocationUpdates();
            }
        }
    }

    private fun updateUI() {
        // Location Update UI
        if (currentLocation != null) {
            textView.text = String.format("Latitude:%f Longitude:%f", currentLocation?.latitude, currentLocation?.longitude)
        }
    }

    private fun initGoogleAPIClient() {
        this.googleApiClient = GoogleApiClient.Builder(applicationContext)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build()
    }

    private fun createLocationRequest() {
        locationRequest = LocationRequest()
        locationRequest.interval = 5000
        locationRequest.fastestInterval = 5000
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
    }

    private fun createLocationSettings() {
        val builder : LocationSettingsRequest.Builder = LocationSettingsRequest.Builder()
        if (this.locationRequest != null) {
            builder.addLocationRequest(locationRequest)
            this.locationSettingRequest = builder.build()
        }
    }

    private fun isLocationEnabled(context : Context) : Boolean {
        var locationMode: Int = 0
        var locationProviders: String?

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            try {
                locationMode = Settings.Secure.getInt(context.contentResolver, Settings.Secure.LOCATION_MODE)
                return locationMode != Settings.Secure.LOCATION_MODE_OFF
            } catch(e: Settings.SettingNotFoundException) {
                e.printStackTrace()

            }
            return locationMode != Settings.Secure.LOCATION_MODE_OFF
        } else {
            locationProviders = Settings.Secure.getString(context.contentResolver, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
            return locationProviders != null && locationProviders.isNotEmpty()
        }
    }

    @Throws(SecurityException::class)
    private fun startLocationUpdates() {
        /*
        if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
            if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)) {
                return
            }
        }*/

        LocationServices.FusedLocationApi.requestLocationUpdates(
                googleApiClient,
                locationRequest,
                this).setResultCallback {
                status: Status -> if (status.isSuccess) {
                    print("Success")
                }
                else {
                print("Failed")
                }
        }
    }

    /*
     * GoogleApiClient.ConnectionCallbacks
     */

    override fun onConnected(p0: Bundle?) {
        if (currentLocation == null) {
            try {           // checkselfpermission or SecurityException
                currentLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient)
                // TODO Update UI
                updateUI()
            }
            catch(e : SecurityException) {

            }
        }
    }

    /*
     *  GoogleApiClient.OnConnectionFailedListener
     */

    override fun onConnectionSuspended(p0: Int) {
    }

    override fun onConnectionFailed(p0: ConnectionResult) {
    }

    /*
     * LocationListener
     */

    override fun onLocationChanged(p0: Location?) {
    }

Test

This code is kotlin.(Android Preveiw 3)

Ref

Androidアプリ開発 Google Play services Location Serviceで位置情報を取得する
Android check permission for LocationManager