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) .setPriority(Priority.PRIORITY_HIGH_ACCURACY)
.build() .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()) fusedLocationProviderClient?.requestLocationUpdates(request, getLocationUpdateIntent())
} }
} }

View file

@ -16,6 +16,10 @@ import javax.inject.Inject
@SuppressLint("VisibleForTests") // https://issuetracker.google.com/issues/239451111 @SuppressLint("VisibleForTests") // https://issuetracker.google.com/issues/239451111
class WearOnboardingListener : WearableListenerService() { class WearOnboardingListener : WearableListenerService() {
companion object {
private const val TAG = "WearOnboardingListener"
}
@Inject @Inject
lateinit var serverManager: ServerManager lateinit var serverManager: ServerManager
@ -41,8 +45,16 @@ class WearOnboardingListener : WearableListenerService() {
setUrgent() setUrgent()
asPutDataRequest() asPutDataRequest()
} }
Wearable.getDataClient(this@WearOnboardingListener).putDataItem(putDataReq).addOnCompleteListener { try {
Log.d("WearOnboardingListener", "sendHomeAssistantInstance: ${if (it.isSuccessful) "success" else "failed"}") 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.") Log.d(TAG, "Registering for activity updates.")
val fastUpdate = SensorReceiverBase.shouldDoFastUpdates(context) val fastUpdate = SensorReceiverBase.shouldDoFastUpdates(context)
try {
actReg.requestActivityUpdates(TimeUnit.MINUTES.toMillis(if (fastUpdate) 1 else 2), pendingIntent) 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 (( if ((
isEnabled(context, sleepConfidence) || isEnabled( isEnabled(context, sleepConfidence) || isEnabled(
@ -238,31 +242,24 @@ class ActivitySensorManager : BroadcastReceiver(), SensorManager {
) { ) {
val pendingIntent = getSleepPendingIntent(context) val pendingIntent = getSleepPendingIntent(context)
Log.d(TAG, "Registering for sleep updates") Log.d(TAG, "Registering for sleep updates")
try {
val task = when { val task = when {
( (isEnabled(context, sleepConfidence) && !isEnabled(context, sleepSegment)) -> {
isEnabled(context, sleepConfidence) && !isEnabled(
context,
sleepSegment
)
) -> {
Log.d(TAG, "Registering for sleep confidence updates only") Log.d(TAG, "Registering for sleep confidence updates only")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates( ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent, pendingIntent,
SleepSegmentRequest(SleepSegmentRequest.CLASSIFY_EVENTS_ONLY) SleepSegmentRequest(SleepSegmentRequest.CLASSIFY_EVENTS_ONLY)
) )
} }
(
!isEnabled(context, sleepConfidence) && isEnabled( (!isEnabled(context, sleepConfidence) && isEnabled(context, sleepSegment)) -> {
context,
sleepSegment
)
) -> {
Log.d(TAG, "Registering for sleep segment updates only") Log.d(TAG, "Registering for sleep segment updates only")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates( ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent, pendingIntent,
SleepSegmentRequest(SleepSegmentRequest.SEGMENT_EVENTS_ONLY) SleepSegmentRequest(SleepSegmentRequest.SEGMENT_EVENTS_ONLY)
) )
} }
else -> { else -> {
Log.d(TAG, "Registering for both sleep confidence and segment updates") Log.d(TAG, "Registering for both sleep confidence and segment updates")
ActivityRecognition.getClient(context).requestSleepSegmentUpdates( ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
@ -280,6 +277,9 @@ class ActivitySensorManager : BroadcastReceiver(), SensorManager {
ActivityRecognition.getClient(context).removeSleepSegmentUpdates(pendingIntent) ActivityRecognition.getClient(context).removeSleepSegmentUpdates(pendingIntent)
sleepRegistration = false 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.content.Context
import android.os.Build import android.os.Build
import android.util.Log
import androidx.car.app.connection.CarConnection import androidx.car.app.connection.CarConnection
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import io.homeassistant.companion.android.common.sensors.SensorManager import io.homeassistant.companion.android.common.sensors.SensorManager
@ -56,7 +57,12 @@ class AndroidAutoSensorManager : SensorManager, Observer<Int> {
} }
CoroutineScope(Dispatchers.Main + Job()).launch { CoroutineScope(Dispatchers.Main + Job()).launch {
if (carConnection == null) { 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) carConnection?.type?.observeForever(this@AndroidAutoSensorManager)
} }

View file

@ -75,7 +75,12 @@ class GeocodeSensorManager : SensorManager {
return 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 var address: Address? = null
try { try {
if (location == null) { if (location == null) {
@ -128,7 +133,13 @@ class GeocodeSensorManager : SensorManager {
val prettyAddress = address?.getAddressLine(0) 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( onSensorUpdated(
context, context,

View file

@ -647,7 +647,13 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
} }
Log.d(TAG, "Registering for location updates.") 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) val intent = getLocationUpdateIntent(false)
fusedLocationProviderClient?.requestLocationUpdates( fusedLocationProviderClient?.requestLocationUpdates(
@ -1109,6 +1115,7 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
setMaxUpdates(maxRetries) setMaxUpdates(maxRetries)
setMinUpdateIntervalMillis(5000) setMinUpdateIntervalMillis(5000)
}.build() }.build()
try {
LocationServices.getFusedLocationProviderClient(latestContext) LocationServices.getFusedLocationProviderClient(latestContext)
.requestLocationUpdates( .requestLocationUpdates(
request, request,
@ -1133,16 +1140,27 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
when { when {
locationResult.lastLocation!!.accuracy <= minAccuracy -> { locationResult.lastLocation!!.accuracy <= minAccuracy -> {
Log.d(TAG, "Location accurate enough, all done with high accuracy.") Log.d(
TAG,
"Location accurate enough, all done with high accuracy."
)
runBlocking { runBlocking {
locationResult.lastLocation?.let { locationResult.lastLocation?.let {
getEnabledServers(latestContext, singleAccurateLocation).forEach { serverId -> getEnabledServers(
sendLocationUpdate(it, serverId, LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION) latestContext,
singleAccurateLocation
).forEach { serverId ->
sendLocationUpdate(
it,
serverId,
LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION
)
} }
} }
} }
if (wakeLock?.isHeld == true) wakeLock.release() if (wakeLock?.isHeld == true) wakeLock.release()
} }
numberCalls >= maxRetries -> { numberCalls >= maxRetries -> {
Log.d( Log.d(
TAG, TAG,
@ -1150,13 +1168,21 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
) )
if (locationResult.lastLocation!!.accuracy <= minAccuracy * 2) { if (locationResult.lastLocation!!.accuracy <= minAccuracy * 2) {
runBlocking { runBlocking {
getEnabledServers(latestContext, singleAccurateLocation).forEach { serverId -> getEnabledServers(
sendLocationUpdate(locationResult.lastLocation!!, serverId, LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION) latestContext,
singleAccurateLocation
).forEach { serverId ->
sendLocationUpdate(
locationResult.lastLocation!!,
serverId,
LocationUpdateTrigger.SINGLE_ACCURATE_LOCATION
)
} }
} }
} }
if (wakeLock?.isHeld == true) wakeLock.release() if (wakeLock?.isHeld == true) wakeLock.release()
} }
else -> { else -> {
Log.w( Log.w(
TAG, TAG,
@ -1168,6 +1194,9 @@ class LocationSensorManager : BroadcastReceiver(), SensorManager {
}, },
Looper.getMainLooper() Looper.getMainLooper()
) )
} catch (e: Exception) {
Log.e(TAG, "Failed to get location data for single accurate sensor", e)
}
} }
override fun docsLink(): String { override fun docsLink(): String {

View file

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

View file

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