kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
commit
37e67809af
|
@ -3,12 +3,12 @@ apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-parcelize'
|
apply plugin: 'kotlin-parcelize'
|
||||||
apply plugin: 'kotlinx-serialization'
|
apply plugin: 'kotlinx-serialization'
|
||||||
apply plugin: 'dagger.hilt.android.plugin'
|
apply plugin: 'dagger.hilt.android.plugin'
|
||||||
apply plugin: 'com.google.gms.google-services'
|
|
||||||
apply plugin: 'com.github.triplet.play'
|
apply plugin: 'com.github.triplet.play'
|
||||||
apply plugin: 'de.mobilej.unmock'
|
apply plugin: 'de.mobilej.unmock'
|
||||||
// apply plugin: "app.brant.amazonappstorepublisher"
|
// apply plugin: "app.brant.amazonappstorepublisher"
|
||||||
|
|
||||||
// Apply the Crashlytics Gradle plugin
|
// Firebase Crashlytics
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
apply plugin: 'com.google.firebase.crashlytics'
|
apply plugin: 'com.google.firebase.crashlytics'
|
||||||
|
|
||||||
// protobuf
|
// protobuf
|
||||||
|
@ -38,11 +38,10 @@ android {
|
||||||
}
|
}
|
||||||
compileSdkVersion 31
|
compileSdkVersion 31
|
||||||
// leave undefined to use version plugin wants
|
// leave undefined to use version plugin wants
|
||||||
// buildToolsVersion "30.0.2" // Note: 30.0.2 doesn't yet work on Github actions CI
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.geeksville.mesh"
|
applicationId "com.geeksville.mesh"
|
||||||
minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works)
|
minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works)
|
||||||
targetSdkVersion 30 // 30 can't work until an explicit location permissions dialog is added
|
targetSdkVersion 30
|
||||||
versionCode 20339 // format is Mmmss (where M is 1+the numeric major number
|
versionCode 20339 // format is Mmmss (where M is 1+the numeric major number
|
||||||
versionName "1.3.39"
|
versionName "1.3.39"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
@ -169,18 +168,10 @@ dependencies {
|
||||||
// implementation 'com.google.android.things:androidthings:1.0'
|
// implementation 'com.google.android.things:androidthings:1.0'
|
||||||
implementation 'com.github.mik3y:usb-serial-for-android:3.4.6'
|
implementation 'com.github.mik3y:usb-serial-for-android:3.4.6'
|
||||||
|
|
||||||
// location services
|
|
||||||
implementation 'com.google.android.gms:play-services-location:19.0.1'
|
|
||||||
// For Google Sign-In (owner name accesss)
|
|
||||||
implementation 'com.google.android.gms:play-services-auth:20.2.0'
|
|
||||||
|
|
||||||
// Add the Firebase SDK for Crashlytics.
|
// Add the Firebase SDK for Crashlytics.
|
||||||
implementation 'com.google.firebase:firebase-crashlytics:18.2.6'
|
implementation 'com.google.firebase:firebase-crashlytics:18.2.6'
|
||||||
implementation 'com.google.firebase:firebase-analytics:20.1.0'
|
implementation 'com.google.firebase:firebase-analytics:20.1.0'
|
||||||
|
|
||||||
// geeksville-androidlib
|
|
||||||
// compileOnly 'com.google.android.gms:play-services-base:17.6.0'
|
|
||||||
|
|
||||||
// alas implementation bug deep in the bowels when I tried it for my SyncBluetoothDevice class
|
// alas implementation bug deep in the bowels when I tried it for my SyncBluetoothDevice class
|
||||||
// implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
|
// implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.android.ServiceClient
|
import com.geeksville.mesh.android.ServiceClient
|
||||||
import com.geeksville.mesh.concurrent.handledLaunch
|
import com.geeksville.mesh.concurrent.handledLaunch
|
||||||
import com.geeksville.mesh.android.getMissingPermissions
|
import com.geeksville.mesh.android.getMissingPermissions
|
||||||
|
import com.geeksville.mesh.android.isGooglePlayAvailable
|
||||||
import com.geeksville.mesh.databinding.ActivityMainBinding
|
import com.geeksville.mesh.databinding.ActivityMainBinding
|
||||||
import com.geeksville.mesh.model.BTScanModel
|
import com.geeksville.mesh.model.BTScanModel
|
||||||
import com.geeksville.mesh.model.BluetoothViewModel
|
import com.geeksville.mesh.model.BluetoothViewModel
|
||||||
|
@ -45,8 +46,6 @@ import com.geeksville.mesh.service.*
|
||||||
import com.geeksville.mesh.ui.*
|
import com.geeksville.mesh.ui.*
|
||||||
import com.geeksville.mesh.util.Exceptions
|
import com.geeksville.mesh.util.Exceptions
|
||||||
import com.geeksville.mesh.util.exceptionReporter
|
import com.geeksville.mesh.util.exceptionReporter
|
||||||
import com.google.android.gms.common.ConnectionResult
|
|
||||||
import com.google.android.gms.common.GoogleApiAvailability
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
|
@ -252,15 +251,12 @@ class MainActivity : BaseActivity(), Logging {
|
||||||
private fun askToRate() {
|
private fun askToRate() {
|
||||||
exceptionReporter { // Got one IllegalArgumentException from inside this lib, but we don't want to crash our app because of bugs in this optional feature
|
exceptionReporter { // Got one IllegalArgumentException from inside this lib, but we don't want to crash our app because of bugs in this optional feature
|
||||||
|
|
||||||
val hasGooglePlay = GoogleApiAvailability.getInstance()
|
|
||||||
.isGooglePlayServicesAvailable(this) != ConnectionResult.SERVICE_MISSING
|
|
||||||
|
|
||||||
val rater = AppRate.with(this)
|
val rater = AppRate.with(this)
|
||||||
.setInstallDays(10.toByte()) // default is 10, 0 means install day, 10 means app is launched 10 or more days later than installation
|
.setInstallDays(10.toByte()) // default is 10, 0 means install day, 10 means app is launched 10 or more days later than installation
|
||||||
.setLaunchTimes(10.toByte()) // default is 10, 3 means app is launched 3 or more times
|
.setLaunchTimes(10.toByte()) // default is 10, 3 means app is launched 3 or more times
|
||||||
.setRemindInterval(1.toByte()) // default is 1, 1 means app is launched 1 or more days after neutral button clicked
|
.setRemindInterval(1.toByte()) // default is 1, 1 means app is launched 1 or more days after neutral button clicked
|
||||||
.setRemindLaunchesNumber(1.toByte()) // default is 0, 1 means app is launched 1 or more times after neutral button clicked
|
.setRemindLaunchesNumber(1.toByte()) // default is 0, 1 means app is launched 1 or more times after neutral button clicked
|
||||||
.setStoreType(if (hasGooglePlay) StoreType.GOOGLEPLAY else StoreType.AMAZON)
|
.setStoreType(StoreType.GOOGLEPLAY)
|
||||||
|
|
||||||
rater.monitor() // Monitors the app launch times
|
rater.monitor() // Monitors the app launch times
|
||||||
|
|
||||||
|
@ -310,7 +306,7 @@ class MainActivity : BaseActivity(), Logging {
|
||||||
// Handle any intent
|
// Handle any intent
|
||||||
handleIntent(intent)
|
handleIntent(intent)
|
||||||
|
|
||||||
askToRate()
|
if (isGooglePlayAvailable(this)) askToRate()
|
||||||
|
|
||||||
// if (!isInTestLab) - very important - even in test lab we must request permissions because we need location perms for some of our tests to pass
|
// if (!isInTestLab) - very important - even in test lab we must request permissions because we need location perms for some of our tests to pass
|
||||||
requestPermission()
|
requestPermission()
|
||||||
|
|
|
@ -10,11 +10,11 @@ import android.provider.Settings
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import com.geeksville.mesh.analytics.AnalyticsProvider
|
import com.geeksville.mesh.analytics.AnalyticsProvider
|
||||||
import com.google.android.gms.common.ConnectionResult
|
import com.google.android.gms.common.ConnectionResult
|
||||||
import com.google.android.gms.common.GoogleApiAvailability
|
import com.google.android.gms.common.GoogleApiAvailabilityLight
|
||||||
|
|
||||||
|
|
||||||
fun isGooglePlayAvailable(context: Context): Boolean {
|
fun isGooglePlayAvailable(context: Context): Boolean {
|
||||||
val a = GoogleApiAvailability.getInstance()
|
val a = GoogleApiAvailabilityLight.getInstance()
|
||||||
val r = a.isGooglePlayServicesAvailable(context)
|
val r = a.isGooglePlayServicesAvailable(context)
|
||||||
return r != ConnectionResult.SERVICE_MISSING && r != ConnectionResult.SERVICE_INVALID
|
return r != ConnectionResult.SERVICE_MISSING && r != ConnectionResult.SERVICE_INVALID
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
package com.geeksville.mesh.android
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.os.Bundle
|
|
||||||
import com.google.android.gms.common.api.Api
|
|
||||||
import com.google.android.gms.common.api.Api.ApiOptions.NotRequiredOptions
|
|
||||||
import com.google.android.gms.common.api.Scope
|
|
||||||
import com.google.android.gms.common.api.GoogleApiClient
|
|
||||||
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks
|
|
||||||
import com.google.android.gms.common.ConnectionResult
|
|
||||||
import com.google.android.gms.common.GooglePlayServicesUtil
|
|
||||||
import android.content.IntentSender
|
|
||||||
import android.content.Intent
|
|
||||||
import android.util.Log
|
|
||||||
|
|
||||||
|
|
||||||
interface PlayClientCallbacks /* : Activity */ {
|
|
||||||
/**
|
|
||||||
* Called to tell activity we've lost connection to play
|
|
||||||
*/
|
|
||||||
fun onPlayConnectionSuspended() :Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called to tell activity we are now connected to play
|
|
||||||
* Do remaining init here
|
|
||||||
*/
|
|
||||||
fun onPlayConnected() : Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when this machine does not have a valid form of play.
|
|
||||||
*/
|
|
||||||
fun onPlayUnavailable() : Unit
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by kevinh on 1/5/15.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class PlayClient(val context: Activity, val playCallbacks: PlayClientCallbacks) : Logging {
|
|
||||||
|
|
||||||
var apiClient: GoogleApiClient? = null
|
|
||||||
var authInProgress: Boolean = false
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val PLAY_OAUTH_REQUEST_CODE = 901
|
|
||||||
val AUTH_PENDING = "authPend"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Must be called from onCreate
|
|
||||||
*/
|
|
||||||
fun playOnCreate(savedInstanceState: Bundle?, apis: Array<Api<out NotRequiredOptions>>, scopes: Array<Scope> = arrayOf()) {
|
|
||||||
|
|
||||||
if(savedInstanceState != null)
|
|
||||||
authInProgress = savedInstanceState.getBoolean(AUTH_PENDING)
|
|
||||||
|
|
||||||
if(hasPlayServices()) {
|
|
||||||
var builder = GoogleApiClient.Builder(context)
|
|
||||||
.addConnectionCallbacks(object : GoogleApiClient.ConnectionCallbacks {
|
|
||||||
|
|
||||||
override fun onConnected(p0: Bundle?) {
|
|
||||||
// Connected to Google Play services!
|
|
||||||
// The good stuff goes here.
|
|
||||||
|
|
||||||
playCallbacks.onPlayConnected()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onConnectionSuspended(i: Int) {
|
|
||||||
// If your connection to the sensor gets lost at some point,
|
|
||||||
// you'll be able to determine the reason and react to it here.
|
|
||||||
if (i == ConnectionCallbacks.CAUSE_NETWORK_LOST) {
|
|
||||||
info("Connection lost. Cause: Network Lost.");
|
|
||||||
} else if (i == ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
|
|
||||||
info("Connection lost. Reason: Service Disconnected");
|
|
||||||
} else
|
|
||||||
errormsg("Unknown play kode $i")
|
|
||||||
|
|
||||||
playCallbacks.onPlayConnectionSuspended()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.addOnConnectionFailedListener(object : GoogleApiClient.OnConnectionFailedListener {
|
|
||||||
override fun onConnectionFailed(result: ConnectionResult) {
|
|
||||||
info("Play connection failed $result")
|
|
||||||
if (!result.hasResolution()) {
|
|
||||||
showErrorDialog(result.errorCode)
|
|
||||||
} else {
|
|
||||||
// The failure has a resolution. Resolve it.
|
|
||||||
// Called typically when the app is not yet authorized, and an
|
|
||||||
// authorization dialog is displayed to the user.
|
|
||||||
if (!authInProgress) {
|
|
||||||
try {
|
|
||||||
info("Attempting to resolve failed connection");
|
|
||||||
authInProgress = true;
|
|
||||||
result.startResolutionForResult(context,
|
|
||||||
PLAY_OAUTH_REQUEST_CODE);
|
|
||||||
} catch (e: IntentSender.SendIntentException) {
|
|
||||||
errormsg("Exception while starting resolution activity")
|
|
||||||
playCallbacks.onPlayUnavailable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
apis.forEach { api ->
|
|
||||||
builder = builder.addApi(api)
|
|
||||||
}
|
|
||||||
|
|
||||||
scopes.forEach { s ->
|
|
||||||
builder = builder.addScope(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
apiClient = builder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showErrorDialog(code: Int) {
|
|
||||||
// Show the localized error dialog
|
|
||||||
GooglePlayServicesUtil.getErrorDialog(code,
|
|
||||||
context, 0)?.show();
|
|
||||||
playCallbacks.onPlayUnavailable()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasPlayServices(): Boolean {
|
|
||||||
// Check that Google Play services is available
|
|
||||||
val resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context)
|
|
||||||
// For testing
|
|
||||||
//val resultCode = ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED
|
|
||||||
|
|
||||||
if (ConnectionResult.SUCCESS == resultCode) {
|
|
||||||
// In debug mode, log the status
|
|
||||||
Log.d("Geofence Detection",
|
|
||||||
"Google Play services is available.");
|
|
||||||
|
|
||||||
// getAnalytics().track("Has Play")
|
|
||||||
|
|
||||||
// Continue
|
|
||||||
return true
|
|
||||||
// Google Play services was not available for some reason
|
|
||||||
} else {
|
|
||||||
showErrorDialog(resultCode)
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Must be called from onActivityResult
|
|
||||||
* @return true if we handled this
|
|
||||||
*/
|
|
||||||
fun playOnActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean =
|
|
||||||
if (requestCode == PLAY_OAUTH_REQUEST_CODE) {
|
|
||||||
authInProgress = false;
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
// Make sure the app is not already connected or attempting to connect
|
|
||||||
if (!apiClient!!.isConnecting && !apiClient!!.isConnected) {
|
|
||||||
apiClient!!.connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// User opted to not install play
|
|
||||||
errormsg("User declined play")
|
|
||||||
context.finish()
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else
|
|
||||||
false
|
|
||||||
|
|
||||||
fun playOnStart() {
|
|
||||||
if(apiClient != null)
|
|
||||||
apiClient!!.connect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playOnStop() {
|
|
||||||
if(apiClient != null && apiClient!!.isConnected)
|
|
||||||
apiClient!!.disconnect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun playSaveInstanceState(outState: Bundle) {
|
|
||||||
outState.putBoolean(AUTH_PENDING, authInProgress)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,14 +3,11 @@ package com.geeksville.mesh.repository.location
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.location.Location
|
import android.location.Location
|
||||||
import android.os.Looper
|
import android.location.LocationListener
|
||||||
|
import android.location.LocationManager
|
||||||
import com.geeksville.mesh.android.GeeksvilleApplication
|
import com.geeksville.mesh.android.GeeksvilleApplication
|
||||||
import com.geeksville.mesh.android.Logging
|
import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.android.hasBackgroundPermission
|
import com.geeksville.mesh.android.hasBackgroundPermission
|
||||||
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 kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
@ -35,47 +32,43 @@ class SharedLocationManager constructor(
|
||||||
val receivingLocationUpdates: StateFlow<Boolean> get() = _receivingLocationUpdates
|
val receivingLocationUpdates: StateFlow<Boolean> get() = _receivingLocationUpdates
|
||||||
|
|
||||||
// TODO use positionBroadcastSecs / test locationRequest settings
|
// TODO use positionBroadcastSecs / test locationRequest settings
|
||||||
private val desiredInterval = 1 * 60 * 1000L
|
|
||||||
// if unset, use positionBroadcastSecs default
|
// if unset, use positionBroadcastSecs default
|
||||||
// positionBroadcastSecs.takeIf { it != 0L }?.times(1000L) ?: (15 * 60 * 1000L)
|
// positionBroadcastSecs.takeIf { it != 0L }?.times(1000L) ?: (15 * 60 * 1000L)
|
||||||
|
private val fastestInterval = 30 * 1000L
|
||||||
// Set up the Fused Location Provider and LocationRequest
|
private val smallestDisplacement = 50F // 50 meters
|
||||||
private val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
|
|
||||||
private val locationRequest = LocationRequest.create().apply {
|
|
||||||
interval = desiredInterval
|
|
||||||
fastestInterval = 30 * 1000L
|
|
||||||
// smallestDisplacement = 50F // 50 meters
|
|
||||||
priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
private val _locationUpdates = callbackFlow {
|
private val _locationUpdates = callbackFlow {
|
||||||
val callback = object : LocationCallback() {
|
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
||||||
override fun onLocationResult(result: LocationResult) {
|
val callback = LocationListener { location ->
|
||||||
// info("New location: ${result.lastLocation}")
|
// info("New location: ${result.lastLocation}")
|
||||||
trySend(result.lastLocation)
|
trySend(location)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.hasBackgroundPermission()) close()
|
if (!context.hasBackgroundPermission()) close()
|
||||||
|
|
||||||
info("Starting location requests with interval=${desiredInterval}ms")
|
|
||||||
|
info("Starting location updates with minTime=${fastestInterval}ms and minDistance=${smallestDisplacement}m")
|
||||||
_receivingLocationUpdates.value = true
|
_receivingLocationUpdates.value = true
|
||||||
GeeksvilleApplication.analytics.track("location_start") // Figure out how many users needed to use the phone GPS
|
GeeksvilleApplication.analytics.track("location_start") // Figure out how many users needed to use the phone GPS
|
||||||
|
|
||||||
fusedLocationClient.requestLocationUpdates(
|
try {
|
||||||
locationRequest,
|
locationManager.requestLocationUpdates(
|
||||||
|
LocationManager.GPS_PROVIDER,
|
||||||
|
fastestInterval,
|
||||||
|
smallestDisplacement,
|
||||||
callback,
|
callback,
|
||||||
Looper.getMainLooper()
|
context.mainLooper
|
||||||
).addOnFailureListener { ex ->
|
)
|
||||||
errormsg("Failed to listen to GPS error: ${ex.message}")
|
} catch (e: Exception) {
|
||||||
close(ex) // in case of exception, close the Flow
|
close(e) // in case of exception, close the Flow
|
||||||
}
|
}
|
||||||
|
|
||||||
awaitClose {
|
awaitClose {
|
||||||
info("Stopping location requests")
|
info("Stopping location requests")
|
||||||
_receivingLocationUpdates.value = false
|
_receivingLocationUpdates.value = false
|
||||||
GeeksvilleApplication.analytics.track("location_stop")
|
GeeksvilleApplication.analytics.track("location_stop")
|
||||||
fusedLocationClient.removeLocationUpdates(callback) // clean up when Flow collection ends
|
locationManager.removeUpdates(callback) // clean up when Flow collection ends
|
||||||
}
|
}
|
||||||
}.shareIn(
|
}.shareIn(
|
||||||
externalScope,
|
externalScope,
|
||||||
|
|
|
@ -9,7 +9,6 @@ import androidx.core.content.edit
|
||||||
import com.geeksville.mesh.analytics.DataPair
|
import com.geeksville.mesh.analytics.DataPair
|
||||||
import com.geeksville.mesh.android.GeeksvilleApplication
|
import com.geeksville.mesh.android.GeeksvilleApplication
|
||||||
import com.geeksville.mesh.android.Logging
|
import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.android.isGooglePlayAvailable
|
|
||||||
import com.geeksville.mesh.concurrent.handledLaunch
|
import com.geeksville.mesh.concurrent.handledLaunch
|
||||||
import com.geeksville.mesh.*
|
import com.geeksville.mesh.*
|
||||||
import com.geeksville.mesh.MeshProtos.MeshPacket
|
import com.geeksville.mesh.MeshProtos.MeshPacket
|
||||||
|
@ -153,7 +152,7 @@ class MeshService : Service(), Logging {
|
||||||
// If we're already observing updates, don't register again
|
// If we're already observing updates, don't register again
|
||||||
if (locationFlow?.isActive == true) return
|
if (locationFlow?.isActive == true) return
|
||||||
|
|
||||||
if (hasBackgroundPermission() && isGooglePlayAvailable(this)) {
|
if (hasBackgroundPermission()) {
|
||||||
locationFlow = locationRepository.getLocations()
|
locationFlow = locationRepository.getLocations()
|
||||||
.onEach { location ->
|
.onEach { location ->
|
||||||
sendPosition(
|
sendPosition(
|
||||||
|
|
|
@ -16,7 +16,6 @@ import com.geeksville.mesh.analytics.DataPair
|
||||||
import com.geeksville.mesh.android.GeeksvilleApplication
|
import com.geeksville.mesh.android.GeeksvilleApplication
|
||||||
import com.geeksville.mesh.android.Logging
|
import com.geeksville.mesh.android.Logging
|
||||||
import com.geeksville.mesh.android.hideKeyboard
|
import com.geeksville.mesh.android.hideKeyboard
|
||||||
import com.geeksville.mesh.android.isGooglePlayAvailable
|
|
||||||
import com.geeksville.mesh.MainActivity
|
import com.geeksville.mesh.MainActivity
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
import com.geeksville.mesh.ConfigProtos
|
import com.geeksville.mesh.ConfigProtos
|
||||||
|
@ -154,7 +153,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
||||||
model.provideLocation.value = false
|
model.provideLocation.value = false
|
||||||
binding.provideLocationCheckbox.isChecked = false
|
binding.provideLocationCheckbox.isChecked = false
|
||||||
} else {
|
} else {
|
||||||
binding.provideLocationCheckbox.isEnabled = isGooglePlayAvailable(requireContext())
|
binding.provideLocationCheckbox.isEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the region selection from the device
|
// update the region selection from the device
|
||||||
|
@ -582,7 +581,7 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
||||||
scanModel.setupScan()
|
scanModel.setupScan()
|
||||||
|
|
||||||
// system permissions might have changed while we were away
|
// system permissions might have changed while we were away
|
||||||
binding.provideLocationCheckbox.isChecked = myActivity.hasBackgroundPermission() && (model.provideLocation.value ?: false) && isGooglePlayAvailable(requireContext())
|
binding.provideLocationCheckbox.isChecked = myActivity.hasBackgroundPermission() && (model.provideLocation.value ?: false)
|
||||||
|
|
||||||
myActivity.registerReceiver(updateProgressReceiver, updateProgressFilter)
|
myActivity.registerReceiver(updateProgressReceiver, updateProgressFilter)
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,7 @@ buildscript {
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
||||||
// Add the Crashlytics Gradle plugin.
|
// Firebase Crashlytics
|
||||||
// Check that you have the Google Services Gradle plugin v4.3.2 or later
|
|
||||||
// (if not, add it).
|
|
||||||
classpath 'com.google.gms:google-services:4.3.10'
|
classpath 'com.google.gms:google-services:4.3.10'
|
||||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue