I cannot fetch the location using LocationManager.GPS_PROVIDER. But it is working with LocationManager.NETWORK_PROVIDER.
val locationManager=getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,500, 100F,listener)//It's working if i use NETWORK_PROVIDER
val listener=object :LocationListener {
override fun onLocationChanged(location: Location?) {
latitude = location!!.latitude.toString()
longitude = location!!.longitude.toString()
Log.d("location", "$latitude $longitude")
}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
}
override fun onProviderEnabled(provider: String?) {
}
override fun onProviderDisabled(provider: String?) {
}
}
Two Solutions:
1. Maybe your GPS location is switched off in your mobile device. So try to switch it ON and check location.
2. Try to implement Fused location provider which is provided by Google Play Services API as it improves performance, saves battery life and provides more accurate location
Related
I am using FusedLocationProviderClient to get the location but it not giving correct Location (i.e. precise). The location it provides is 20 blocks away atleast which is not really a good solution for me.
LatLng i Need : 28.602205, 77.380126
LatLng i receive: 28.600504,77.382864
Here is code for the same
val client = LocationServices.getFusedLocationProviderClient(this)
var locationRequest = LocationRequest.create().apply {
interval = TimeUnit.SECONDS.toMillis(20)
}
client.requestLocationUpdates(locationRequest, object: LocationCallback() {
override fun onLocationAvailability(p0: LocationAvailability) {
super.onLocationAvailability(p0)
}
override fun onLocationResult(p0: LocationResult) {
super.onLocationResult(p0)
var latLong = p0.lastLocation
marker.position = LatLng(latLong!!.latitude, latLong.longitude)
Log.d("sagar", "Location result: $p0")
}
}, Looper.getMainLooper())
I follow this question to do the offline speech on android.
I downloaded the language in google voice and it can work in offline.
The problem is that I want to know it's current running on offline or online speech, (just like Apple speech to text, there is an api to check for that) to display the speech stream in my app correctly
I wonder is there anyway to do that?
Here is my code:
val intentSpeech = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intentSpeech.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US")
intentSpeech = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intentSpeech.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
intentSpeech.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
intentSpeech.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
packageName)
val recognizer = SpeechRecognizer.createSpeechRecognizer(this)
recognizer.setRecognitionListener(this)
P/s: I can see the Read Along app by google works perfectly in offline or online mode.
I'm trying to do the same with the android speech api. Is it possible?
For offline speech to text, you can use Google's default STT model but it seems to be non-continuous.
private fun startSpeechToText() {
val speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this)
val speechRecognizerIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
speechRecognizerIntent.putExtra(
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
)
speechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
speechRecognizer.setRecognitionListener(object : RecognitionListener {
override fun onReadyForSpeech(bundle: Bundle?) {}
override fun onBeginningOfSpeech() {}
override fun onRmsChanged(v: Float) {}
override fun onBufferReceived(bytes: ByteArray?) {}
override fun onEndOfSpeech() {}
override fun onError(i: Int) {}
override fun onResults(bundle: Bundle) {
val result = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
if (result != null) {
// result[0] will give the output of speech
}
}
override fun onPartialResults(bundle: Bundle) {}
override fun onEvent(i: Int, bundle: Bundle?) {}
})
// starts listening ...
speechRecognizer.startListening(speechRecognizerIntent)
}
If you don't want to use google as it requires to download the offline model for speech to text.
The other option for offline STT is the Vosk API as it has pretrained models in english and other language for live STT.
https://github.com/alphacep/vosk-android-demo
Reference: https://www.geeksforgeeks.org/offline-speech-to-text-without-any-popup-dialog-in-android/
//THIS IS THE CUSTOM OBJECT CLASS myLocation
package com.hari.keralacovidtracker.Models
open class myLocation(val lat:String, val long:String) {
override fun toString(): String {
return super.toString()
}
}
//I AM TRYING TO STORE LOCATION OBJECT IN INTERNAL STORAGE
//BELOW IS THE LOCATION LISTENER CODE
lateinit var locarray:Array<myLocation>
private val locationListener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
val latitude= location.latitude.toString()
val longitude= location.longitude.toString()
val loc= object:myLocation(latitude,longitude){}
}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {}
}
I want to load this loc object to my apps internal storage and also don't know how to read the data from internal storage the new object is created every time the person change location and it need to be saved in internal storage and any way to access it efficiently?
I am getting the error None of the following functions can be called with the arguments supplied when trying to call requestLocationUpdates() using Kotlin. I've gotten this issue before in other places and have been able to fix it, but I'm not able to in this case. I'm relatively new to the language and don't fully understand the issue here.
The issue is with the LocationListener that is passed in. It is expecting a LocationListener!, but apparently that isn't what it's getting.
Here is the snippet of code:
private var locationManager: LocationManager? = null
private var latitude: Double? = null
private var longitude: Double? = null
//private val locationListener: com.google.android.gms.location.LocationListener
private val locationListener: com.google.android.gms.location.LocationListener = object : com.google.android.gms.location.LocationListener {
override fun onLocationChanged(location: Location) {
latitude = location.latitude
longitude = location.longitude
}
}
init {
// Initialize Places.
Places.initialize(activity, BuildConfig.googlePlacesAPI_KEY)
Places.createClient(activity)
locationManager = activity.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 50f, locationListener)
if (locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
getLocation(activity)
}
}
You are using the wrong LocationListener. Because you're not using the FusedLocationProviderClient you should be using the android.location.LocationListener instead and implement all methods.
private val locationListener = object : android.location.LocationListener {
override fun onProviderEnabled(provider: String?) {}
override fun onProviderDisabled(provider: String?) {}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
Log.d("status = $status")
}
override fun onLocationChanged(location: Location?) {
latitude = location?.latitude
longitude = location?.longitude
}
}
I'd suggest you to use the fused location provider instead of the android location service because it is simpler to implement. In fact, it is exactly what Google recommends. See the developer guides below...
https://developer.android.com/training/location/receive-location-updates
I'm quite new to Kotlin coroutine and Android development in general.
While playing around to understand how it worked, I faced an error I can't seem to solve.
From a basic activity i try to connect to the googleApiClient. The permissions are ok.
I wish to use kotlin coroutines to get location updates from LocationManager in a direct style to use this Location object later on.
The first time I changed my position in the emulator it works fine, the second time I change my position, It crashes
with an exception like this:
FATAL EXCEPTION: main
Process: com.link_value.eventlv, PID: 32404
java.lang.IllegalStateException: Already resumed, but got value Location[gps 48.783000,2.516180 acc=20 et=+59m16s372ms alt=0.0 {Bundle[mParcelledData.dataSize=40]}]
at kotlinx.coroutines.experimental.AbstractContinuation.resumeImpl(AbstractContinuation.kt:79)
at kotlinx.coroutines.experimental.AbstractContinuation.resume(AbstractContinuation.kt:72)
at com.link_value.eventlv.View.Create.NewEventLvActivity$await$2$1.onLocationChanged(NewEventLvActivity.kt:100)
at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:297)
at android.location.LocationManager$ListenerTransport.-wrap0(LocationManager.java)
at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:242)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_event_lv)
askForUserLocation()
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val presenter = CreateEventPresenterImpl(this#NewEventLvActivity)
googleApiClient = GoogleApiClient.Builder(this#NewEventLvActivity)
.enableAutoManage(this /* FragmentActivity */,
this /* OnConnectionFailedListener */)
.addApi(Places.GEO_DATA_API)
.addConnectionCallbacks(this)
.build()
}
override fun onConnected(p0: Bundle?) {
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
input_address.addTextChangedListener(object: TextWatcher{
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(query: CharSequence?, p1: Int, p2: Int, p3: Int) {
if (query.toString().length >= 4) {
launch(UI) {
val locationUpdated = locationManager.await(LocationManager.GPS_PROVIDER)
input_name.text = Editable.Factory.getInstance().newEditable(locationUpdated.toString())
}
}
}
})
}
private suspend fun LocationManager.await(locationProvider: String): Location? = suspendCoroutine { cont ->
try {
requestLocationUpdates(locationProvider, 0, 0.toFloat(), object : LocationListener {
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
override fun onProviderEnabled(p0: String?) {
}
override fun onProviderDisabled(p0: String?) {
cont.resumeWithException(UnknownLocationException())
}
override fun onLocationChanged(location: Location?) {
cont.resume(location)
}
})
} catch (ex: SecurityException) {
cont.resumeWithException(ex)
}
}
It's as if Kotlin use the same Continuation. I don't know what I'm doing wrong and why it crashes the second time. Can someone enlighten me.
Thks in advance.
According to documentation, it's possible to resume Continuation only single time. Second resume will throw IllegalStateException with "Already resumed, but got $proposedUpdate" message. You can add additional checking continuation.isActive to prevent this exception. It's better to use Channels for multiple callbacks like location updates.
I had this issue recently with one of 3rd party APIs we use in our project. The problem was solely on the side of the API as the callback was called more than once in the underlying implementation and unsubscribe method wasn't immedeately removing callback from the API.
So, approach I picked was just simply to add a boolean flag. Although, it could've been solved in a bit more elegant way with Kotlin's Flow.mapLatest/collectLatest or so.
suspend fun singularContentUpdate(): Data =
suspendCancellableCoroutine { continuation ->
var resumed = false
val callback = object : Callback {
override fun onDataReady(d: Data) {
api.unsubscribe(this)
if (!resumed) {
continuation.resume(d)
resumed = true
}
}
}
continuation.invokeOnCancellation {
api.unsubscribe(callback)
}
api.subscribe(subscriber)
api.refresh()
}
You can use this function to prevent this exception.
import kotlinx.coroutines.CancellableContinuation
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
inline fun <T> Continuation<T>.safeResume(value: T, onExceptionCalled: () -> Unit) {
if (this is CancellableContinuation) {
if (isActive)
resume(value)
else
onExceptionCalled()
} else throw Exception("Must use suspendCancellableCoroutine instead of suspendCoroutine")
}
Notice that I'll throw an exception if you're using suspendCoroutine instead of suspendCancellableCoroutine.
Usage:
suspend fun getId() : Result<String> = suspendCancellableCoroutine { continuation ->
...
continuation.safeResume(Result.success(adjustID)) { Timber.e("Job has already done") }
}