Catch potential play services errors (#4019)

This commit is contained in:
Daniel Shokouhi 2023-11-22 10:12:47 -08:00 committed by GitHub
parent e44cbf0113
commit 1aa56166c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 224 additions and 124 deletions

View File

@ -194,7 +194,12 @@ class HighAccuracyLocationService : Service() {
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
.build()
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
fusedLocationProviderClient = try {
LocationServices.getFusedLocationProviderClient(this)
} catch (e: Exception) {
Log.e(TAG, "Unable to get fused location provider client", e)
null
}
fusedLocationProviderClient?.requestLocationUpdates(request, getLocationUpdateIntent())
}
}

View File

@ -16,6 +16,10 @@ import javax.inject.Inject
@SuppressLint("VisibleForTests") // https://issuetracker.google.com/issues/239451111
class WearOnboardingListener : WearableListenerService() {
companion object {
private const val TAG = "WearOnboardingListener"
}
@Inject
lateinit var serverManager: ServerManager
@ -41,8 +45,16 @@ class WearOnboardingListener : WearableListenerService() {
setUrgent()
asPutDataRequest()
}
Wearable.getDataClient(this@WearOnboardingListener).putDataItem(putDataReq).addOnCompleteListener {
Log.d("WearOnboardingListener", "sendHomeAssistantInstance: ${if (it.isSuccessful) "success" else "failed"}")
try {
Wearable.getDataClient(this@WearOnboardingListener).putDataItem(putDataReq)
.addOnCompleteListener {
Log.d(
TAG,
"sendHomeAssistantInstance: ${if (it.isSuccessful) "success" else "failed"}"
)
}
} catch (e: Exception) {
Log.e(TAG, "Failed to send home assistant instance", e)
}
}
}

View File

@ -227,7 +227,11 @@ class ActivitySensorManager : BroadcastReceiver(), SensorManager {
Log.d(TAG, "Registering for activity updates.")
val fastUpdate = SensorReceiverBase.shouldDoFastUpdates(context)
actReg.requestActivityUpdates(TimeUnit.MINUTES.toMillis(if (fastUpdate) 1 else 2), pendingIntent)
try {
actReg.requestActivityUpdates(TimeUnit.MINUTES.toMillis(if (fastUpdate) 1 else 2), pendingIntent)
} catch (e: Exception) {
Log.e(TAG, "Unable to register for activity updates", e)
}
}
if ((
isEnabled(context, sleepConfidence) || isEnabled(
@ -238,47 +242,43 @@ class ActivitySensorManager : BroadcastReceiver(), SensorManager {
) {
val pendingIntent = getSleepPendingIntent(context)
Log.d(TAG, "Registering for sleep updates")
val task = when {
(
isEnabled(context, sleepConfidence) && !isEnabled(
context,
sleepSegment
)
) -> {
Log.d(TAG, "Registering for sleep confidence updates only")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest(SleepSegmentRequest.CLASSIFY_EVENTS_ONLY)
)
try {
val task = when {
(isEnabled(context, sleepConfidence) && !isEnabled(context, sleepSegment)) -> {
Log.d(TAG, "Registering for sleep confidence updates only")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest(SleepSegmentRequest.CLASSIFY_EVENTS_ONLY)
)
}
(!isEnabled(context, sleepConfidence) && isEnabled(context, sleepSegment)) -> {
Log.d(TAG, "Registering for sleep segment updates only")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest(SleepSegmentRequest.SEGMENT_EVENTS_ONLY)
)
}
else -> {
Log.d(TAG, "Registering for both sleep confidence and segment updates")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest.getDefaultSleepSegmentRequest()
)
}
}
(
!isEnabled(context, sleepConfidence) && isEnabled(
context,
sleepSegment
)
) -> {
Log.d(TAG, "Registering for sleep segment updates only")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest(SleepSegmentRequest.SEGMENT_EVENTS_ONLY)
)
task.addOnSuccessListener {
Log.d(TAG, "Successfully registered for sleep updates")
sleepRegistration = true
}
else -> {
Log.d(TAG, "Registering for both sleep confidence and segment updates")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest.getDefaultSleepSegmentRequest()
)
task.addOnFailureListener {
Log.e(TAG, "Failed to register for sleep updates", it)
ActivityRecognition.getClient(context).removeSleepSegmentUpdates(pendingIntent)
sleepRegistration = false
}
}
task.addOnSuccessListener {
Log.d(TAG, "Successfully registered for sleep updates")
sleepRegistration = true
}
task.addOnFailureListener {
Log.e(TAG, "Failed to register for sleep updates", it)
ActivityRecognition.getClient(context).removeSleepSegmentUpdates(pendingIntent)
sleepRegistration = false
} catch (e: Exception) {
Log.e(TAG, "Unable to register for sleep updates", e)
}
}
}

View File

@ -2,6 +2,7 @@ package io.homeassistant.companion.android.sensors
import android.content.Context
import android.os.Build
import android.util.Log
import androidx.car.app.connection.CarConnection
import androidx.lifecycle.Observer
import io.homeassistant.companion.android.common.sensors.SensorManager
@ -56,7 +57,12 @@ class AndroidAutoSensorManager : SensorManager, Observer<Int> {
}
CoroutineScope(Dispatchers.Main + Job()).launch {
if (carConnection == null) {
carConnection = CarConnection(context.applicationContext)
carConnection = try {
CarConnection(context.applicationContext)
} catch (e: Exception) {
Log.e(TAG, "Failed to get car connection", e)
null
}
}
carConnection?.type?.observeForever(this@AndroidAutoSensorManager)
}

View File

@ -75,7 +75,12 @@ class GeocodeSensorManager : SensorManager {
return
}
val location = LocationServices.getFusedLocationProviderClient(context).lastLocation.await()
val location = try {
LocationServices.getFusedLocationProviderClient(context).lastLocation.await()
} catch (e: Exception) {
Log.e(TAG, "Failed to get fused location provider client", e)
null
}
var address: Address? = null
try {
if (location == null) {
@ -128,7 +133,13 @@ class GeocodeSensorManager : SensorManager {
val prettyAddress = address?.getAddressLine(0)
HighAccuracyLocationService.updateNotificationAddress(context, location, if (!prettyAddress.isNullOrEmpty()) prettyAddress else context.getString(commonR.string.unknown_address))
if (location != null) {
HighAccuracyLocationService.updateNotificationAddress(
context,
location,
if (!prettyAddress.isNullOrEmpty()) prettyAddress else context.getString(commonR.string.unknown_address)
)
}
onSensorUpdated(
context,

View File

@ -647,7 +647,13 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
}
Log.d(TAG, "Registering for location updates.")
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(latestContext)
fusedLocationProviderClient = try {
LocationServices.getFusedLocationProviderClient(latestContext)
} catch (e: Exception) {
Log.e(TAG, "Unable to get fused location provider client", e)
null
}
val intent = getLocationUpdateIntent(false)
fusedLocationProviderClient?.requestLocationUpdates(
@ -1109,65 +1115,88 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
setMaxUpdates(maxRetries)
setMinUpdateIntervalMillis(5000)
}.build()
LocationServices.getFusedLocationProviderClient(latestContext)
.requestLocationUpdates(
request,
object : LocationCallback() {
val wakeLock: PowerManager.WakeLock? =
latestContext.getSystemService<PowerManager>()
?.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"HomeAssistant::AccurateLocation"
)?.apply { acquire(10 * 60 * 1000L /*10 minutes*/) }
var numberCalls = 0
override fun onLocationResult(locationResult: LocationResult) {
numberCalls++
Log.d(
TAG,
"Got single accurate location update: ${locationResult.lastLocation}"
)
if (locationResult.equals(null)) {
Log.w(TAG, "No location provided.")
return
}
try {
LocationServices.getFusedLocationProviderClient(latestContext)
.requestLocationUpdates(
request,
object : LocationCallback() {
val wakeLock: PowerManager.WakeLock? =
latestContext.getSystemService<PowerManager>()
?.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
"HomeAssistant::AccurateLocation"
)?.apply { acquire(10 * 60 * 1000L /*10 minutes*/) }
var numberCalls = 0
override fun onLocationResult(locationResult: LocationResult) {
numberCalls++
Log.d(
TAG,
"Got single accurate location update: ${locationResult.lastLocation}"
)
if (locationResult.equals(null)) {
Log.w(TAG, "No location provided.")
return
}
when {
locationResult.lastLocation!!.accuracy <= minAccuracy -> {
Log.d(TAG, "Location accurate enough, all done with high accuracy.")
runBlocking {
locationResult.lastLocation?.let {
getEnabledServers(latestContext, singleAccurateLocation).forEach { serverId ->
sendLocationUpdate(it, serverId, LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION)
}
}
}
if (wakeLock?.isHeld == true) wakeLock.release()
}
numberCalls >= maxRetries -> {
Log.d(
TAG,
"No location was accurate enough, sending our last location anyway"
)
if (locationResult.lastLocation!!.accuracy <= minAccuracy * 2) {
when {
locationResult.lastLocation!!.accuracy <= minAccuracy -> {
Log.d(
TAG,
"Location accurate enough, all done with high accuracy."
)
runBlocking {
getEnabledServers(latestContext, singleAccurateLocation).forEach { serverId ->
sendLocationUpdate(locationResult.lastLocation!!, serverId, LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION)
locationResult.lastLocation?.let {
getEnabledServers(
latestContext,
singleAccurateLocation
).forEach { serverId ->
sendLocationUpdate(
it,
serverId,
LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION
)
}
}
}
if (wakeLock?.isHeld == true) wakeLock.release()
}
numberCalls >= maxRetries -> {
Log.d(
TAG,
"No location was accurate enough, sending our last location anyway"
)
if (locationResult.lastLocation!!.accuracy <= minAccuracy * 2) {
runBlocking {
getEnabledServers(
latestContext,
singleAccurateLocation
).forEach { serverId ->
sendLocationUpdate(
locationResult.lastLocation!!,
serverId,
LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION
)
}
}
}
if (wakeLock?.isHeld == true) wakeLock.release()
}
else -> {
Log.w(
TAG,
"Location not accurate enough on retry $numberCalls of $maxRetries"
)
}
if (wakeLock?.isHeld == true) wakeLock.release()
}
else -> {
Log.w(
TAG,
"Location not accurate enough on retry $numberCalls of $maxRetries"
)
}
}
}
},
Looper.getMainLooper()
)
},
Looper.getMainLooper()
)
} catch (e: Exception) {
Log.e(TAG, "Failed to get location data for single accurate sensor", e)
}
}
override fun docsLink(): String {

View File

@ -34,9 +34,9 @@ class SettingsWearActivity : AppCompatActivity(), CapabilityClient.OnCapabilityC
private lateinit var binding: ActivitySettingsWearBinding
private lateinit var capabilityClient: CapabilityClient
private lateinit var nodeClient: NodeClient
private lateinit var remoteActivityHelper: RemoteActivityHelper
private var capabilityClient: CapabilityClient? = null
private var nodeClient: NodeClient? = null
private var remoteActivityHelper: RemoteActivityHelper? = null
private var wearNodesWithApp: Set<Node>? = null
private var allConnectedNodes: List<Node>? = null
@ -49,9 +49,24 @@ class SettingsWearActivity : AppCompatActivity(), CapabilityClient.OnCapabilityC
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
capabilityClient = Wearable.getCapabilityClient(this)
nodeClient = Wearable.getNodeClient(this)
remoteActivityHelper = RemoteActivityHelper(this)
capabilityClient = try {
Wearable.getCapabilityClient(this)
} catch (e: Exception) {
Log.e(TAG, "Unable to get capability client", e)
null
}
nodeClient = try {
Wearable.getNodeClient(this)
} catch (e: Exception) {
Log.e(TAG, "Unable to get node client", e)
null
}
remoteActivityHelper = try {
RemoteActivityHelper(this)
} catch (e: Exception) {
Log.e(TAG, "Unable to get remote activity helper", e)
null
}
binding.remoteOpenButton.setOnClickListener {
openPlayStoreOnWearDevicesWithoutApp()
@ -81,13 +96,13 @@ class SettingsWearActivity : AppCompatActivity(), CapabilityClient.OnCapabilityC
override fun onPause() {
super.onPause()
capabilityClient.removeListener(this, CAPABILITY_WEAR_APP)
capabilityClient?.removeListener(this, CAPABILITY_WEAR_APP)
}
override fun onResume() {
super.onResume()
title = getString(commonR.string.wear_os_settings_title)
capabilityClient.addListener(this, CAPABILITY_WEAR_APP)
capabilityClient?.addListener(this, CAPABILITY_WEAR_APP)
}
/*
@ -106,11 +121,11 @@ class SettingsWearActivity : AppCompatActivity(), CapabilityClient.OnCapabilityC
private suspend fun findWearDevicesWithApp() {
try {
val capabilityInfo = capabilityClient
.getCapability(CAPABILITY_WEAR_APP, CapabilityClient.FILTER_ALL)
.await()
?.getCapability(CAPABILITY_WEAR_APP, CapabilityClient.FILTER_ALL)
?.await()
withContext(Dispatchers.Main) {
wearNodesWithApp = capabilityInfo.nodes
wearNodesWithApp = capabilityInfo?.nodes
Log.d(TAG, "Capable Nodes: $wearNodesWithApp")
updateUI()
}
@ -124,7 +139,7 @@ class SettingsWearActivity : AppCompatActivity(), CapabilityClient.OnCapabilityC
private suspend fun findAllWearDevices() {
try {
val connectedNodes = nodeClient.connectedNodes.await()
val connectedNodes = nodeClient?.connectedNodes?.await()
withContext(Dispatchers.Main) {
allConnectedNodes = connectedNodes
@ -187,11 +202,11 @@ class SettingsWearActivity : AppCompatActivity(), CapabilityClient.OnCapabilityC
lifecycleScope.launch {
try {
remoteActivityHelper
.startRemoteActivity(
?.startRemoteActivity(
targetIntent = intent,
targetNodeId = node.id
)
.await()
?.await()
Toast.makeText(
this@SettingsWearActivity,

View File

@ -84,7 +84,11 @@ class SettingsWearViewModel @Inject constructor(
val resultSnackbar = _resultSnackbar.asSharedFlow()
init {
Wearable.getDataClient(application).addListener(this)
try {
Wearable.getDataClient(application).addListener(this)
} catch (e: Exception) {
Log.e(TAG, "Unable to get wearable data client", e)
}
viewModelScope.launch {
try {
val capabilityInfo = Wearable.getCapabilityClient(application)
@ -113,7 +117,11 @@ class SettingsWearViewModel @Inject constructor(
}
override fun onCleared() {
Wearable.getDataClient(getApplication<HomeAssistantApplication>()).removeListener(this)
try {
Wearable.getDataClient(getApplication<HomeAssistantApplication>()).removeListener(this)
} catch (e: Exception) {
Log.e(TAG, "Unable to remove listener from wearable data client", e)
}
if (serverId != 0) {
CoroutineScope(Dispatchers.Main + Job()).launch {
@ -218,15 +226,18 @@ class SettingsWearViewModel @Inject constructor(
}
val app = getApplication<HomeAssistantApplication>()
Wearable.getDataClient(app).putDataItem(putDataRequest).apply {
addOnSuccessListener { Log.d(TAG, "Successfully sent auth to wear") }
addOnFailureListener { e ->
Log.e(TAG, "Failed to send auth to wear", e)
_hasData.value = true
viewModelScope.launch {
_resultSnackbar.emit(app.getString(commonR.string.failed_watch_connection))
try {
Wearable.getDataClient(app).putDataItem(putDataRequest).apply {
addOnSuccessListener { Log.d(TAG, "Successfully sent auth to wear") }
addOnFailureListener { e ->
Log.e(TAG, "Failed to send auth to wear", e)
_hasData.value = true
watchConnectionError(app)
}
}
} catch (e: Exception) {
Log.e(TAG, "Unable to send auth to wear", e)
watchConnectionError(app)
}
}
@ -238,9 +249,14 @@ class SettingsWearViewModel @Inject constructor(
asPutDataRequest()
}
Wearable.getDataClient(getApplication<HomeAssistantApplication>()).putDataItem(putDataRequest).apply {
addOnSuccessListener { Log.d(TAG, "Successfully sent tile template to wear") }
addOnFailureListener { e -> Log.e(TAG, "Failed to send tile template to wear", e) }
try {
Wearable.getDataClient(getApplication<HomeAssistantApplication>())
.putDataItem(putDataRequest).apply {
addOnSuccessListener { Log.d(TAG, "Successfully sent tile template to wear") }
addOnFailureListener { e -> Log.e(TAG, "Failed to send tile template to wear", e) }
}
} catch (e: Exception) {
Log.e(TAG, "Unable to send template tile to wear", e)
}
}
@ -348,4 +364,10 @@ class SettingsWearViewModel @Inject constructor(
authenticateId = null
}
private fun watchConnectionError(app: HomeAssistantApplication) {
viewModelScope.launch {
_resultSnackbar.emit(app.getString(commonR.string.failed_watch_connection))
}
}
}