I created new application as location log app. but it's no response when I send latitude and longitude in AVD's extended control. so what can I fix code in Android Manifest?

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

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>

            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
    <service android:name=".LocationService"/>
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version"/>
        <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value= />

</application>

MainActivity.kt

package com.example.android.sample.location

import android.app.DatePickerDialog
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import android.os.PersistableBundle
import android.support.v4.app.DialogFragment
import android.support.v7.app.AppCompatActivity
import android.text.format.DateFormat
import android.widget.DatePicker
import android.widget.TextView
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.*
import java.util.*


class MainActivity : AppCompatActivity(), DatePickerDialog.OnDateSetListener {

    private var currentDate = Calendar.getInstance()
    private lateinit var googleMap : GoogleMap

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

        if (savedInstanceState != null && savedInstanceState.containsKey("currentDate")) {
            currentDate = savedInstanceState.getSerializable("currentDate") as Calendar
        }

        val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync {
            googleMap = it
            renderMap()
        }

        showCurrentDate()
    }

    override fun onSaveInstanceState(outState: Bundle?, outPersistentState: PersistableBundle?) {
        super.onSaveInstanceState(outState, outPersistentState)
        outState?.putSerializable("currentDate", currentDate)
    }

    private fun renderMap() {
        val locations = selectInDay(this,
            currentDate[Calendar.YEAR], currentDate[Calendar.MONTH], currentDate[Calendar.DATE])

        zoomTo(googleMap, locations)
        putMarkers(googleMap, locations)
    }

    private fun zoomTo(map: GoogleMap, locations : List<LocationRecord>) {
        if (locations.size == 1) {
            val latLng = LatLng(locations[0].latitude, locations[0].longitude)

            val move = CameraUpdateFactory.newLatLngZoom(latLng, 15f)
            map.moveCamera(move)

        } else if (locations.size > 1) {
            val bounds = LatLngBounds.Builder()
            locations.forEach { location ->
                bounds.include(LatLng(location.latitude, location.longitude))
            }

            val padding = (50 * resources.displayMetrics.density).toInt()

            val move = 
CameraUpdateFactory.newLatLngBounds(bounds.build(),
                resources.displayMetrics.widthPixels,
                resources.displayMetrics.heightPixels,
                padding)

            map.moveCamera(move)
        }
    }

    private fun putMarkers(map: GoogleMap, locations: List<LocationRecord>) {

        map.clear()

        val lineOptions = PolylineOptions()

        locations.forEach { location ->
            val latLng = LatLng(location.latitude, location.longitude)

            lineOptions.add(latLng)


            val marker = MarkerOptions()
                .position(latLng) 
                .draggable(false) 


            val descriptor = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)
            marker.icon(descriptor)


            map.addMarker(marker)
        }


        map.addPolyline(lineOptions)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == 1) {
            val switchFragment = supportFragmentManager.findFragmentById(R.id.switch_fragment)
            switchFragment?.onActivityResult(requestCode, resultCode, data)
        }
    }

    private fun showCurrentDate() {
        val dateView = findViewById<TextView>(R.id.date)
        dateView.setOnClickListener{

            val dialog = DatePickerFragment()
            dialog.arguments = Bundle().apply {
                putSerializable("current", currentDate)
            }
            dialog.show(supportFragmentManager, "calendar")
        }

        dateView.setText(DateFormat.format("MM dd", currentDate.time))
    }

    override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {

        currentDate.set(year, month, dayOfMonth)
        renderMap()
        showCurrentDate()
    }
}

class DatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener {

    private lateinit var calendar : Calendar

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        calendar = arguments?.getSerializable("current") as? Calendar ?: Calendar.getInstance()
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return DatePickerDialog(context, this,
            calendar[Calendar.YEAR], calendar[Calendar.MONTH], calendar[Calendar.DATE])
    }

    override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int) {
        if (context is DatePickerDialog.OnDateSetListener) {
            (context as DatePickerDialog.OnDateSetListener).onDateSet(view, year, month, day)
        }
    }
}

LocationService.kt

package com.example.android.sample.location

import android.app.IntentService
import android.content.Intent
import com.google.android.gms.location.LocationResult

class LocationService : IntentService("LocationService") {
    override fun onHandleIntent(intent: Intent?) {
        val result = LocationResult.extractResult(intent)
        if (result != null) {
            insertLocations(this, result.locations)
        }
    }
}

LocationDatabase.kt

package com.example.android.sample.location

import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.location.Location
import java.util.*

private const val DB_NAME = "LocationDatabase"
private const val DB_VERSION = 1

class LocationDatabase(context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL("""
            CREATE TABLE Locations (
            _id INTEGER PRIMARY KEY AUTOINCREMENT,
            latitude REAL NOT NULL,
            longitude REAL NOT NULL,
            time INTEGER NOT NULL);
            """)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
    }
}

class LocationRecord(val id : Long, val latitude : Double, val longitude : Double, val time : Long)

fun selectInDay(context: Context, year: Int, month: Int, day : Int) : List<LocationRecord> {

    val calendar = Calendar.getInstance()
    calendar.set(year, month, day, 0, 0, 0)
    val from = calendar.time.time.toString()
    calendar.add(Calendar.DATE, 1)      
    val to = calendar.time.time.toString()

    val database = LocationDatabase(context).readableDatabase

    val cursor = database.query("Locations", null,
        "time > ? AND time < ?", arrayOf(from, to),
        null, null, "time DESC")

    val locations = mutableListOf<LocationRecord>()
    cursor.use {
        while(cursor.moveToNext()) {
            val place = LocationRecord(
                cursor.getLong(cursor.getColumnIndex("_id")),
                cursor.getDouble(cursor.getColumnIndex("latitude")),
                cursor.getDouble(cursor.getColumnIndex("longitude")),
                cursor.getLong(cursor.getColumnIndex("time")))
            locations.add(place)
        }
    }

    database.close()
    return locations
}

fun insertLocations(context: Context, locations : List<Location>) {
    val database = LocationDatabase(context).writableDatabase

    database.use { db ->
        locations.filter { !it.isFromMockProvider }
            .forEach { location ->
                val record = ContentValues().apply {
                    put("latitude", location.latitude)
                    put("longitude", location.longitude)
                    put("time", location.time)
                }

                db.insert("Locations", null, record)
            }
    }
}

SwitchFragment.kt

package com.example.android.sample.location

import android.Manifest
import android.app.Activity
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Switch
import android.widget.Toast
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.LocationSettingsRequest
import com.google.android.gms.location.LocationSettingsStatusCodes
import java.util.concurrent.TimeUnit


class SwitchFragment : Fragment() {

    private fun checkLocationAvailable() {

        val act = activity ?: return

        val checkRequest = LocationSettingsRequest.Builder().addLocationRequest(
            getLocationRequest()).build()
        val checkTask = LocationServices.getSettingsClient(act).
                checkLocationSettings(checkRequest)

        checkTask.addOnCompleteListener { response ->
            try {
                response.getResult(ApiException::class.java)

                checkLocationPermission()
                } catch (exception: ApiException) {

                if (exception.statusCode ==
                        LocationSettingsStatusCodes.RESOLUTION_REQUIRED) {

                    val resolvable = exception as ResolvableApiException
                    resolvable.startResolutionForResult(activity, 1)
                } else {
                    showErrorMessage()
                }
            }
        }
    }


    private fun checkLocationPermission() {

        val ctx = context ?: return

        if (ContextCompat.checkSelfPermission(ctx,
                Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {

            val intent = Intent(ctx, LocationService::class.java)
            val service = PendingIntent.getService(ctx, 1, intent,
                PendingIntent.FLAG_UPDATE_CURRENT)
            LocationServices.getFusedLocationProviderClient(ctx)
                .requestLocationUpdates(getLocationRequest(), service)

            ctx.getSharedPreferences("LocationRequesting",
                Context.MODE_PRIVATE)
                .edit().putBoolean("isRequesting", true).apply()
        } else {

            requestPermissions(arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION), 1)
        }
    }


    private fun showErrorMessage() {
        Toast.makeText(context, "it's not possible to get location information.",
            Toast.LENGTH_SHORT).show()
        activity?.finish()
    }

    private fun getLocationRequest() =
            LocationRequest()

                .setInterval(TimeUnit.MINUTES.toMillis(5))

                .setFastestInterval(TimeUnit.MINUTES.toMillis(1))

                .setMaxWaitTime(TimeUnit.MINUTES.toMillis(20))
                .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
    {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) {

            checkLocationPermission()
        } else {

            showErrorMessage()
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int,
                                           permissions: Array<out String>,
                                           grantResults: IntArray) {
        if (permissions.isNotEmpty() && grantResults[0] ==
                PackageManager.PERMISSION_GRANTED) {

            checkLocationPermission()
        } else {

            showErrorMessage()
        }
    }

    private fun stopLocationRequest() {
        val ctx = context ?: return
        val intent = Intent(ctx, LocationService::class.java)
        val service = PendingIntent.getService(ctx, 1,
            intent, PendingIntent.FLAG_UPDATE_CURRENT)
        LocationServices.getFusedLocationProviderClient(ctx)
            .removeLocationUpdates(service)

        ctx.getSharedPreferences("LocationRequesting", Context.MODE_PRIVATE)
            .edit().putBoolean("isRequesting", true).apply()
    }

    override fun onCreateView(inflater: LayoutInflater,
                              container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_switch, container, false)
        val switch = view.findViewById<Switch>(R.id.locationSwitch)


        val isRequesting = context?.getSharedPreferences(
            "LocationRequesting", Context.MODE_PRIVATE
        )
            ?.getBoolean("isRequesting", false) ?: false
        switch.isChecked = isRequesting


        switch.setOnCheckedChangeListener { _,isChecked ->
            if (isChecked) {
                checkLocationAvailable()
            } else {
                stopLocationRequest()
            }
        }
        return view
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<fragment
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="0dp"
        android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" android:id="@+id/map"/>
<fragment
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:name="com.example.android.sample.location.SwitchFragment"
        android:id="@+id/switch_fragment"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp" tools:layout="@layout/fragment_switch"/>
<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/date"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        tools:text="December 31th"
        app:layout_constraintTop_toTopOf="parent" android:layout_marginStart="8dp"
        app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="8dp"/>

fragment_switch.xml

<?xml version="1.0" encoding="utf-8"?>

<Switch
        android:text="@string/locationInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/locationSwitch"
        app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp"
        app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
        app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp" android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"/>

I already add API_KEY from GCP.I can build the app and it worked in android studio 3.4. just my sending location info is not able to reflect to emulator.

0 Answers