Update/replace deprecations in app module (#3661)

This commit is contained in:
Joris Pelgröm 2023-07-17 14:08:20 +02:00 committed by GitHub
parent 33dfc69949
commit bc103636db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 233 additions and 120 deletions

View file

@ -188,12 +188,11 @@ class HighAccuracyLocationService : Service() {
@SuppressLint("MissingPermission")
private fun requestLocationUpdates(intervalInSeconds: Int) {
val request = LocationRequest.create()
val intervalInMS = (intervalInSeconds * 1000).toLong()
request.interval = intervalInMS
request.fastestInterval = intervalInMS / 2
request.priority = Priority.PRIORITY_HIGH_ACCURACY
val request = LocationRequest.Builder(intervalInMS)
.setMinUpdateIntervalMillis(intervalInMS / 2)
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
.build()
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
fusedLocationProviderClient?.requestLocationUpdates(request, getLocationUpdateIntent())

View file

@ -1,5 +1,6 @@
package io.homeassistant.companion.android.onboarding
import android.annotation.SuppressLint
import android.util.Log
import com.google.android.gms.wearable.MessageEvent
import com.google.android.gms.wearable.PutDataMapRequest
@ -12,6 +13,7 @@ import kotlinx.coroutines.runBlocking
import javax.inject.Inject
@AndroidEntryPoint
@SuppressLint("VisibleForTests") // https://issuetracker.google.com/issues/239451111
class WearOnboardingListener : WearableListenerService() {
@Inject
@ -34,7 +36,7 @@ class WearOnboardingListener : WearableListenerService() {
if (url != null) {
// Put as DataMap in data layer
val putDataReq: PutDataRequest = PutDataMapRequest.create("/home_assistant_instance").run {
dataMap.putString("name", url?.host.toString())
dataMap.putString("name", url.host.toString())
dataMap.putString("url", url.toString())
setUrgent()
asPutDataRequest()

View file

@ -162,6 +162,7 @@ class GeocodeSensorManager : SensorManager {
)
}
} else {
@Suppress("DEPRECATION")
getFromLocation(latitude, longitude, maxResults).orEmpty()
}
}

View file

@ -194,10 +194,9 @@ class LocationSensorManager : LocationSensorManagerBase() {
ACTION_PROCESS_GEO -> handleGeoUpdate(intent)
ACTION_REQUEST_ACCURATE_LOCATION_UPDATE -> requestSingleAccurateLocation()
ACTION_FORCE_HIGH_ACCURACY -> {
var command = intent.extras?.get("command")?.toString()
when (command) {
when (val command = intent.extras?.getString("command")) {
DeviceCommandData.TURN_ON, DeviceCommandData.TURN_OFF, MessagingManager.FORCE_ON -> {
var turnOn = command != DeviceCommandData.TURN_OFF
val turnOn = command != DeviceCommandData.TURN_OFF
if (turnOn) {
Log.d(TAG, "Forcing of high accuracy mode enabled")
} else {

View file

@ -15,6 +15,7 @@ import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
import io.homeassistant.companion.android.common.util.capitalize
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext

View file

@ -11,6 +11,8 @@ import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
import io.homeassistant.companion.android.common.data.integration.domain
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
import io.homeassistant.companion.android.common.util.capitalize
import java.util.Locale
import io.homeassistant.companion.android.common.R as commonR
@RequiresApi(Build.VERSION_CODES.R)
@ -43,7 +45,7 @@ object DefaultButtonControl : HaControl {
"input_button" -> context.getString(commonR.string.domain_input_button)
"scene" -> context.getString(commonR.string.domain_scene)
"script" -> context.getString(commonR.string.domain_script)
else -> entity.domain.replaceFirstChar { it.titlecase() }
else -> entity.domain.capitalize(Locale.getDefault())
}
override suspend fun performAction(

View file

@ -9,10 +9,13 @@ import android.service.controls.actions.ControlAction
import android.service.controls.templates.ControlButton
import android.service.controls.templates.ToggleTemplate
import androidx.annotation.RequiresApi
import androidx.compose.ui.text.capitalize
import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
import io.homeassistant.companion.android.common.data.integration.domain
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
import io.homeassistant.companion.android.common.util.capitalize
import java.util.Locale
import io.homeassistant.companion.android.common.R as commonR
@RequiresApi(Build.VERSION_CODES.R)
@ -47,7 +50,7 @@ object DefaultSwitchControl : HaControl {
"automation" -> context.getString(commonR.string.domain_automation)
"input_boolean" -> context.getString(commonR.string.domain_input_boolean)
"switch" -> context.getString(commonR.string.domain_switch)
else -> entity.domain.replaceFirstChar { it.titlecase() }
else -> entity.domain.capitalize(Locale.getDefault())
}
override suspend fun performAction(

View file

@ -11,6 +11,8 @@ import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.IntegrationRepository
import io.homeassistant.companion.android.common.data.integration.domain
import io.homeassistant.companion.android.common.data.websocket.impl.entities.AreaRegistryResponse
import io.homeassistant.companion.android.common.util.capitalize
import java.util.Locale
@RequiresApi(Build.VERSION_CODES.R)
object HaFailedControl : HaControl {
@ -35,7 +37,7 @@ object HaFailedControl : HaControl {
DeviceTypes.TYPE_UNKNOWN
override fun getDomainString(context: Context, entity: Entity<Map<String, Any>>): String =
entity.domain.replaceFirstChar { it.titlecase() }
entity.domain.capitalize(Locale.getDefault())
override suspend fun performAction(
integrationRepository: IntegrationRepository,

View file

@ -11,6 +11,7 @@ import android.nfc.NfcAdapter
import android.nfc.Tag
import android.nfc.tech.Ndef
import android.nfc.tech.NdefFormatable
import android.os.Build
import io.homeassistant.companion.android.BuildConfig
import java.io.IOException
@ -20,7 +21,12 @@ object NFCUtil {
return null
}
val rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
val rawMessages = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, NdefMessage::class.java)
} else {
@Suppress("DEPRECATION")
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
}
val ndefMessage = rawMessages?.get(0) as NdefMessage?
return ndefMessage?.records?.get(0)?.toUri()
}
@ -35,7 +41,12 @@ object NFCUtil {
val nfcMessage = NdefMessage(arrayOf(nfcRecord) + applicationRecords)
val nfcFallbackMessage = NdefMessage(arrayOf(nfcRecord))
intent?.let {
val tag = it.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
val tag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
it.getParcelableExtra(NfcAdapter.EXTRA_TAG, Tag::class.java)
} else {
@Suppress("DEPRECATION")
it.getParcelableExtra(NfcAdapter.EXTRA_TAG)
}
return writeMessageToTag(nfcMessage, nfcFallbackMessage, tag)
}
return false

View file

@ -839,10 +839,10 @@ class MessagingManager @Inject constructor(
name,
value.split(";").map { it.toBoolean() }.toBooleanArray()
)
"char" -> intent.putExtra(name, value[0].toChar())
"char" -> intent.putExtra(name, value[0])
"char[]" -> intent.putExtra(
name,
value.split(";").map { it[0].toChar() }.toCharArray()
value.split(";").map { it[0] }.toCharArray()
)
"String" -> intent.putExtra(name, value)
"String.urlencoded", "urlencoded" -> intent.putExtra(

View file

@ -3,6 +3,7 @@ package io.homeassistant.companion.android.notifications
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Handler
import android.util.Log
import android.widget.Toast
@ -44,8 +45,12 @@ class NotificationActionReceiver : BroadcastReceiver() {
lateinit var notificationDao: NotificationDao
override fun onReceive(context: Context, intent: Intent) {
val notificationAction =
intent.getParcelableExtra<NotificationAction>(EXTRA_NOTIFICATION_ACTION)
val notificationAction = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(EXTRA_NOTIFICATION_ACTION, NotificationAction::class.java)
} else {
@Suppress("DEPRECATION")
intent.getParcelableExtra(EXTRA_NOTIFICATION_ACTION)
}
if (notificationAction == null) {
Log.e(TAG, "Failed to get notification action.")

View file

@ -3,6 +3,7 @@ package io.homeassistant.companion.android.notifications
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationManagerCompat
import dagger.hilt.android.AndroidEntryPoint
@ -33,8 +34,14 @@ class NotificationDeleteReceiver : BroadcastReceiver() {
@Inject
lateinit var notificationDao: NotificationDao
@Suppress("UNCHECKED_CAST")
override fun onReceive(context: Context, intent: Intent) {
val hashData = intent.getSerializableExtra(EXTRA_DATA) as HashMap<String, *>
val hashData = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getSerializableExtra(EXTRA_DATA, HashMap::class.java)
} else {
@Suppress("DEPRECATION")
intent.getSerializableExtra(EXTRA_DATA)
} as HashMap<String, *>
val group = intent.getStringExtra(EXTRA_NOTIFICATION_GROUP)
val groupId = intent.getIntExtra(EXTRA_NOTIFICATION_GROUP_ID, -1)

View file

@ -4,7 +4,6 @@ import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
@ -13,6 +12,7 @@ import android.provider.Settings
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.compose.ui.platform.ComposeView
import androidx.core.content.getSystemService
@ -30,10 +30,8 @@ import io.homeassistant.companion.android.common.R as commonR
@AndroidEntryPoint
class MobileAppIntegrationFragment : Fragment() {
companion object {
private const val BACKGROUND_REQUEST = 99
private const val LOCATION_REQUEST_CODE = 0
private val requestLocationPermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
onLocationPermissionResult(it)
}
private var dialog: AlertDialog? = null
@ -92,54 +90,43 @@ class MobileAppIntegrationFragment : Fragment() {
private fun requestPermissions(sensorId: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
this@MobileAppIntegrationFragment.requestPermissions(
requestLocationPermissions.launch(
LocationSensorManager().requiredPermissions(sensorId)
.toList().minus(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
.toTypedArray(),
LOCATION_REQUEST_CODE
.toTypedArray()
)
} else {
this@MobileAppIntegrationFragment.requestPermissions(
LocationSensorManager().requiredPermissions(sensorId),
LOCATION_REQUEST_CODE
)
requestLocationPermissions.launch(LocationSensorManager().requiredPermissions(sensorId))
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
private fun onLocationPermissionResult(
results: Map<String, Boolean>
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
dialog?.dismiss()
if (permissions.contains(Manifest.permission.ACCESS_FINE_LOCATION) &&
if (
results[Manifest.permission.ACCESS_FINE_LOCATION] == true &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
) {
requestPermissions(
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
LOCATION_REQUEST_CODE
)
requestLocationPermissions.launch(arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION))
return
}
if (requestCode == LOCATION_REQUEST_CODE) {
val hasPermission = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
viewModel.setLocationTracking(hasPermission)
requestBackgroundAccess()
}
val hasPermission = results.values.all { it }
viewModel.setLocationTracking(hasPermission)
requestBackgroundAccess()
}
@SuppressLint("BatteryLife")
private fun requestBackgroundAccess() {
val intent: Intent
if (!isIgnoringBatteryOptimizations()) {
intent = Intent(
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:${activity?.packageName}")
startActivity(
Intent(
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Uri.parse("package:${activity?.packageName}")
)
)
startActivityForResult(intent, BACKGROUND_REQUEST)
}
}

View file

@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton

View file

@ -211,6 +211,7 @@ abstract class TileExtensions : TileService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
vm?.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
} else {
@Suppress("DEPRECATION")
vm?.vibrate(500)
}
}
@ -282,6 +283,7 @@ abstract class TileExtensions : TileService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
vm?.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK))
} else {
@Suppress("DEPRECATION")
vm?.vibrate(1000)
}
}

View file

@ -64,7 +64,12 @@ class LastAppSensorManager : SensorManager {
try {
val pm = context.packageManager
val appInfo = pm.getApplicationInfo(lastApp, PackageManager.GET_META_DATA)
val appInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
pm.getApplicationInfo(lastApp, PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()))
} else {
@Suppress("DEPRECATION")
pm.getApplicationInfo(lastApp, PackageManager.GET_META_DATA)
}
appLabel = pm.getApplicationLabel(appInfo).toString()
} catch (e: Exception) {
Log.e(TAG, "Unable to get package label for: $lastApp", e)

View file

@ -313,6 +313,7 @@ class NotificationSensorManager : NotificationListenerService(), SensorManager {
private fun mappedBundle(bundle: Bundle, keySuffix: String = ""): Map<String, Any?>? {
return try {
bundle.keySet().associate { key ->
@Suppress("DEPRECATION")
val keyValue = when (val value = bundle.get(key)) {
is Array<*> -> {
if (value.all { it is Bundle }) {

View file

@ -32,7 +32,7 @@ class SensorWorker(
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, sensorWorker)
.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, sensorWorker)
}
}

View file

@ -35,6 +35,7 @@ class ManageControlsSettingsFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -1,6 +1,7 @@
package io.homeassistant.companion.android.settings.language
import android.content.Context
import io.homeassistant.companion.android.common.util.capitalize
import java.util.Locale
import javax.inject.Inject
import io.homeassistant.companion.android.common.R as commonR
@ -16,9 +17,7 @@ class LanguagesProvider @Inject constructor(
val locales = langManager.getLocaleTags(context)
locales.forEach {
val locale = makeLocale(it)
var display = locale.getDisplayLanguage(locale).replaceFirstChar { char ->
if (char.isLowerCase()) char.titlecase(locale) else char.toString()
}
var display = locale.getDisplayLanguage(locale).capitalize(Locale.getDefault())
if (locale.country.isNotBlank()) display += " (${locale.getDisplayCountry(locale)})"
listAppLocales[display] = it
}

View file

@ -4,6 +4,7 @@ import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
@ -48,6 +49,7 @@ class LogFragment : Fragment() {
private var crashLog: String? = null
private var currentLog = ""
@Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.share_log -> {
@ -208,7 +210,12 @@ class LogFragment : Fragment() {
private fun getExcludedComponentsForPackageName(sendIntent: Intent, packageNames: Array<String>): ArrayList<ComponentName> {
val excludedComponents = ArrayList<ComponentName>()
val resInfos = requireContext().packageManager.queryIntentActivities(sendIntent, 0)
val resInfos = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requireContext().packageManager.queryIntentActivities(sendIntent, PackageManager.ResolveInfoFlags.of(0))
} else {
@Suppress("DEPRECATION")
requireContext().packageManager.queryIntentActivities(sendIntent, 0)
}
for (resInfo in resInfos) {
val packageName = resInfo.activityInfo.packageName
val name = resInfo.activityInfo.name

View file

@ -28,6 +28,7 @@ class NotificationChannelFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -2,6 +2,7 @@ package io.homeassistant.companion.android.settings.notification
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
@ -34,11 +35,17 @@ class NotificationDetailFragment : Fragment() {
private lateinit var notification: NotificationItem
override fun onCreate(savedInstanceState: Bundle?) {
notification = arguments?.get(ARG_NOTIF) as NotificationItem
notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arguments?.getSerializable(ARG_NOTIF, NotificationItem::class.java)
} else {
@Suppress("DEPRECATION")
arguments?.get(ARG_NOTIF) as? NotificationItem
} ?: return
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
menu.setGroupVisible(R.id.notification_toolbar_group, true)
@ -51,6 +58,7 @@ class NotificationDetailFragment : Fragment() {
}
}
@Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.action_delete) {
deleteConfirmation()

View file

@ -4,10 +4,10 @@ import android.app.AlertDialog
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.Html.fromHtml
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.widget.SearchView
import androidx.core.text.HtmlCompat
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
@ -37,6 +37,7 @@ class NotificationHistoryFragment : PreferenceFragmentCompat() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
menu.setGroupVisible(R.id.notification_toolbar_group, true)
@ -86,6 +87,7 @@ class NotificationHistoryFragment : PreferenceFragmentCompat() {
}
}
@Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val prefCategory = findPreference<PreferenceCategory>("list_notifications")
if (item.itemId in listOf(R.id.last25, R.id.last50, R.id.last100)) {
@ -162,7 +164,7 @@ class NotificationHistoryFragment : PreferenceFragmentCompat() {
cal.timeInMillis = item.received
pref.key = item.id.toString()
pref.title = "${cal.time} - ${item.source}"
pref.summary = fromHtml(item.message)
pref.summary = HtmlCompat.fromHtml(item.message, HtmlCompat.FROM_HTML_MODE_LEGACY)
pref.isIconSpaceReserved = false
pref.setOnPreferenceClickListener {

View file

@ -40,8 +40,11 @@ fun NotificationChannelView(
val context = LocalContext.current
Scaffold(
scaffoldState = scaffoldState
) {
LazyColumn(contentPadding = PaddingValues(16.dp)) {
) { contentPadding ->
LazyColumn(
modifier = Modifier.padding(contentPadding),
contentPadding = PaddingValues(16.dp)
) {
item {
Text(
text = stringResource(id = R.string.notification_channels_description),

View file

@ -1,6 +1,5 @@
package io.homeassistant.companion.android.settings.notification.views
import android.text.Html
import android.widget.TextView
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
@ -16,6 +15,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.text.HtmlCompat
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.ObjectMapper
import io.homeassistant.companion.android.database.notification.NotificationItem
@ -48,7 +48,7 @@ fun LoadNotification(notification: NotificationItem) {
AndroidView(
factory = { context ->
TextView(context).apply {
text = Html.fromHtml(notification.message)
text = HtmlCompat.fromHtml(notification.message, HtmlCompat.FROM_HTML_MODE_LEGACY)
textSize = 16f
}
},

View file

@ -41,6 +41,7 @@ class ManageTilesFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -62,6 +62,7 @@ class SensorDetailFragment : Fragment() {
}
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
menu.setGroupVisible(R.id.senor_detail_toolbar_group, true)

View file

@ -3,6 +3,7 @@ package io.homeassistant.companion.android.settings.sensor
import android.Manifest
import android.app.Application
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.annotation.StringRes
import androidx.compose.runtime.State
@ -375,11 +376,20 @@ class SensorDetailViewModel @Inject constructor(
SensorSettingType.LIST ->
getSettingTranslatedEntries(setting.name, entries ?: setting.entries)
SensorSettingType.LIST_APPS ->
entries ?: getApplication<Application>().packageManager
?.getInstalledApplications(PackageManager.GET_META_DATA)
?.map { packageItem -> packageItem.packageName }
?.sorted()
.orEmpty()
entries ?: run {
val apps = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getApplication<Application>().packageManager
?.getInstalledApplications(PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()))
} else {
@Suppress("DEPRECATION")
getApplication<Application>().packageManager
?.getInstalledApplications(PackageManager.GET_META_DATA)
}
apps
?.map { packageItem -> packageItem.packageName }
?.sorted()
.orEmpty()
}
SensorSettingType.LIST_BLUETOOTH -> {
val devices = BluetoothUtils.getBluetoothDevices(getApplication())
.filter { entries == null || entries.contains(it.address) }
@ -431,7 +441,7 @@ class SensorDetailViewModel @Inject constructor(
// This is only called when we requested permissions to enable a sensor, so check if we
// need to do another request, or if we have all permissions and should enable the sensor.
if (results.keys.contains(Manifest.permission.ACCESS_FINE_LOCATION) &&
android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
) {
permissionRequests.value = PermissionsDialog(serverId, arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION))
return

View file

@ -28,6 +28,7 @@ class SensorSettingsFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
@ -65,6 +66,7 @@ class SensorSettingsFragment : Fragment() {
}
}
@Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_show_sensors_all, R.id.action_show_sensors_enabled, R.id.action_show_sensors_disabled -> {

View file

@ -28,6 +28,7 @@ class SensorUpdateFrequencyFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -42,6 +42,7 @@ class ManageShortcutsSettingsFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -30,6 +30,7 @@ class SsidFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -56,6 +56,7 @@ class WebsocketSettingFragment : Fragment() {
}
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -26,6 +26,7 @@ class ManageWidgetsSettingsFragment : Fragment() {
setHasOptionsMenu(true)
}
@Deprecated("Deprecated in Java")
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)

View file

@ -80,7 +80,7 @@ fun ManageWidgetsView(
onClick = { expandedAddWidget = true }
)
}
}) {
}) { contentPadding ->
if (expandedAddWidget) {
val availableWidgets = listOf(
stringResource(R.string.widget_button_image_description) to WidgetType.BUTTON,
@ -108,7 +108,7 @@ fun ManageWidgetsView(
}
LazyColumn(
contentPadding = PaddingValues(all = 16.dp),
modifier = Modifier.fillMaxWidth()
modifier = Modifier.padding(contentPadding).fillMaxWidth()
) {
if (viewModel.buttonWidgetList.value.isEmpty() && viewModel.staticWidgetList.value.isEmpty() &&
viewModel.mediaWidgetList.value.isEmpty() && viewModel.templateWidgetList.value.isEmpty() &&

View file

@ -1,9 +1,13 @@
package io.homeassistant.companion.android.util
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.util.TypedValue
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
fun Context.getAttribute(attr: Int, fallbackAttr: Int): Int {
val value = TypedValue()
@ -15,3 +19,16 @@ fun Context.getHexForColor(@ColorRes attr: Int): String {
val color = ContextCompat.getColor(this, attr)
return String.format("#%06X", 0xFFFFFF and color) // https://stackoverflow.com/a/6540378
}
/** @return `true` if the device has an active network configured to reach the internet (not validated) */
fun Context.hasActiveConnection(): Boolean {
val cm = getSystemService<ConnectivityManager>() ?: return false
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
cm.activeNetwork?.let {
cm.getNetworkCapabilities(it)?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
} ?: false
} else {
@Suppress("DEPRECATION")
cm.activeNetworkInfo?.isConnected == true
}
}

View file

@ -71,7 +71,6 @@ object DataUriDownloadManager {
.notify(url.hashCode(), notification.build())
}
@Suppress("DEPRECATION")
private suspend fun writeDataUriToFile(
context: Context,
url: String,

View file

@ -1,5 +1,6 @@
package io.homeassistant.companion.android.util
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.view.MotionEvent
@ -11,15 +12,28 @@ import kotlin.math.abs
// Adapted from the system GestureDetector/GestureListener and https://stackoverflow.com/a/26387629
// We need to keep track of (pointer) down, move, (pointer) up and cancel events to be able to detect flings
// (or swipes) and send the direction + number of pointers for that fling to the app
abstract class OnSwipeListener : View.OnTouchListener {
abstract class OnSwipeListener(context: Context?) : View.OnTouchListener {
var handler = Handler(Looper.getMainLooper())
var velocityTracker: VelocityTracker? = null
var downEvent: MotionEvent? = null
var numberOfPointers = 0
var minimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity()
var maximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity()
private var minimumFlingVelocity = 0
private var maximumFlingVelocity = 0
init {
if (context != null) {
val configuration = ViewConfiguration.get(context)
minimumFlingVelocity = configuration.scaledMinimumFlingVelocity
maximumFlingVelocity = configuration.scaledMaximumFlingVelocity
} else {
@Suppress("DEPRECATION")
minimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity()
@Suppress("DEPRECATION")
maximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity()
}
}
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
event?.let { motionEvent ->

View file

@ -32,6 +32,7 @@ import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.domain
import io.homeassistant.companion.android.common.data.integration.getIcon
import io.homeassistant.companion.android.common.data.servers.ServerManager
import io.homeassistant.companion.android.common.util.capitalize
import io.homeassistant.companion.android.launch.LaunchActivity
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
@ -137,9 +138,7 @@ class MainVehicleScreen(
val friendlyDomain =
SUPPORTED_DOMAINS_WITH_STRING[domain]?.let { carContext.getString(it) }
?: domain.split("_").joinToString(" ") { word ->
word.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}
word.capitalize(Locale.getDefault())
}
val icon = Entity(
"$domain.ha_android_placeholder",

View file

@ -5,7 +5,6 @@ import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.os.Build
import android.os.PowerManager
import android.util.Log
@ -31,6 +30,7 @@ import io.homeassistant.companion.android.database.settings.SettingsDao
import io.homeassistant.companion.android.database.settings.WebsocketSetting
import io.homeassistant.companion.android.notifications.MessagingManager
import io.homeassistant.companion.android.settings.SettingsActivity
import io.homeassistant.companion.android.util.hasActiveConnection
import io.homeassistant.companion.android.webview.WebViewActivity
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
@ -66,7 +66,7 @@ class WebsocketManager(
if (workInfo == null || workInfo.state.isFinished || workInfo.state == WorkInfo.State.ENQUEUED) {
workManager.enqueueUniquePeriodicWork(
TAG,
ExistingPeriodicWorkPolicy.REPLACE,
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
websocketNotifications
)
} else {
@ -125,21 +125,18 @@ class WebsocketManager(
private fun shouldWeRun(): Boolean = serverManager.defaultServers.any { shouldRunForServer(it.id) }
@Suppress("DEPRECATION")
private fun shouldRunForServer(serverId: Int): Boolean {
val server = serverManager.getServer(serverId) ?: return false
val setting = settingsDao.get(serverId)?.websocketSetting ?: DEFAULT_WEBSOCKET_SETTING
val isHome = server.connection.isInternal()
// Check for connectivity but not internet access, based on WorkManager's NetworkConnectedController API <26
val connectivityManager = applicationContext.getSystemService<ConnectivityManager>()
val networkInfo = connectivityManager?.activeNetworkInfo
val powerManager = applicationContext.getSystemService<PowerManager>()!!
val displayOff = !powerManager.isInteractive
return when {
(setting == WebsocketSetting.NEVER) -> false
(networkInfo != null && !networkInfo.isConnected) -> false
(!applicationContext.hasActiveConnection()) -> false
!serverManager.isRegistered() -> false
(displayOff && setting == WebsocketSetting.SCREEN_ON) -> false
(!isHome && setting == WebsocketSetting.HOME_WIFI) -> false

View file

@ -276,7 +276,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
onBackPressedDispatcher.addCallback(this, onBackPressed)
webView.apply {
setOnTouchListener(object : OnSwipeListener() {
setOnTouchListener(object : OnSwipeListener(this@WebViewActivity) {
override fun onSwipe(
e1: MotionEvent,
e2: MotionEvent,
@ -318,6 +318,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
settings.mediaPlaybackRequiresUserGesture = !presenter.isAutoPlayVideoEnabled()
settings.userAgentString = settings.userAgentString + " ${HomeAssistantApis.USER_AGENT_STRING}"
webViewClient = object : TLSWebViewClient(keyChainRepository) {
@Deprecated("Deprecated in Java for SDK >= 23")
override fun onReceivedError(
view: WebView?,
errorCode: Int,
@ -998,6 +999,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
webView.performHapticFeedback(HapticFeedbackConstants.CONFIRM)
} else {
@Suppress("DEPRECATION")
vm?.vibrate(500)
}
}
@ -1005,6 +1007,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
vm?.vibrate(VibrationEffect.createOneShot(400, VibrationEffect.EFFECT_HEAVY_CLICK))
} else {
@Suppress("DEPRECATION")
vm?.vibrate(1500)
}
}
@ -1012,6 +1015,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
webView.performHapticFeedback(HapticFeedbackConstants.REJECT)
} else {
@Suppress("DEPRECATION")
vm?.vibrate(1000)
}
}
@ -1028,6 +1032,7 @@ class WebViewActivity : BaseActivity(), io.homeassistant.companion.android.webvi
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
webView.performHapticFeedback(HapticFeedbackConstants.GESTURE_START)
} else {
@Suppress("DEPRECATION")
vm?.vibrate(50)
}
}

View file

@ -7,6 +7,7 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@ -362,7 +363,12 @@ class ButtonWidget : AppWidgetProvider() {
val label: String? = extras.getString(EXTRA_LABEL)
val requireAuthentication: Boolean = extras.getBoolean(EXTRA_REQUIRE_AUTHENTICATION)
val icon: String = extras.getString(EXTRA_ICON_NAME) ?: "mdi:flash"
val backgroundType: WidgetBackgroundType = extras.getSerializable(EXTRA_BACKGROUND_TYPE) as WidgetBackgroundType
val backgroundType: WidgetBackgroundType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
extras.getSerializable(EXTRA_BACKGROUND_TYPE, WidgetBackgroundType::class.java)
} else {
@Suppress("DEPRECATION")
extras.getSerializable(EXTRA_BACKGROUND_TYPE) as? WidgetBackgroundType
} ?: WidgetBackgroundType.DAYNIGHT
val textColor: String? = extras.getString(EXTRA_TEXT_COLOR)
if (serverId == null || domain == null || service == null || serviceData == null) {

View file

@ -34,7 +34,6 @@ import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import dagger.hilt.android.AndroidEntryPoint
import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.Service
import io.homeassistant.companion.android.database.widget.ButtonWidgetDao

View file

@ -7,14 +7,12 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.net.ConnectivityManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.View
import android.widget.RemoteViews
import androidx.core.content.getSystemService
import com.squareup.picasso.Picasso
import dagger.hilt.android.AndroidEntryPoint
import io.homeassistant.companion.android.BuildConfig
@ -22,6 +20,7 @@ import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.common.data.servers.ServerManager
import io.homeassistant.companion.android.database.widget.CameraWidgetDao
import io.homeassistant.companion.android.database.widget.CameraWidgetEntity
import io.homeassistant.companion.android.util.hasActiveConnection
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -71,7 +70,7 @@ class CameraWidget : AppWidgetProvider() {
appWidgetId: Int,
appWidgetManager: AppWidgetManager = AppWidgetManager.getInstance(context)
) {
if (!isConnectionActive(context)) {
if (!context.hasActiveConnection()) {
Log.d(TAG, "Skipping widget update since network connection is not active")
return
}
@ -257,12 +256,6 @@ class CameraWidget : AppWidgetProvider() {
// Enter relevant functionality for when the last widget is disabled
}
private fun isConnectionActive(context: Context): Boolean {
val connectivityManager = context.getSystemService<ConnectivityManager>()
val activeNetworkInfo = connectivityManager?.activeNetworkInfo
return activeNetworkInfo?.isConnected ?: false
}
private fun getScreenWidth(): Int {
return Resources.getSystem().displayMetrics.widthPixels
}

View file

@ -10,7 +10,9 @@ import androidx.core.widget.doAfterTextChanged
import androidx.recyclerview.widget.RecyclerView
import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.Service
import io.homeassistant.companion.android.common.util.capitalize
import io.homeassistant.companion.android.databinding.WidgetButtonConfigureDynamicFieldBinding
import java.util.Locale
import kotlin.Exception
class WidgetDynamicFieldAdapter(
@ -53,13 +55,13 @@ class WidgetDynamicFieldAdapter(
// Set label for the text view
// Reformat text to "Capital Words" instead of "capital_words"
binding.dynamicAutocompleteLabel.text =
fieldKey.split("_").map {
fieldKey.split("_").joinToString(" ") {
if (it == "id") {
it.toUpperCase()
it.uppercase(Locale.getDefault())
} else {
it.capitalize()
it.capitalize(Locale.getDefault())
}
}.joinToString(" ")
}
// If the field has an example, use it as a hint
if (services[serviceText]?.serviceData?.fields?.get(fieldKey)?.example != null) {
@ -200,7 +202,7 @@ class WidgetDynamicFieldAdapter(
private fun String.toBooleanOrNull(): Boolean? {
// Parse all valid YAML boolean values
return when (this.trim().toLowerCase()) {
return when (this.trim().lowercase(Locale.getDefault())) {
"true" -> true
"on" -> true
"yes" -> true

View file

@ -6,6 +6,7 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
@ -193,7 +194,12 @@ class EntityWidget : BaseWidgetProvider() {
val textSizeSelection: String? = extras.getString(EXTRA_TEXT_SIZE)
val stateSeparatorSelection: String? = extras.getString(EXTRA_STATE_SEPARATOR)
val attributeSeparatorSelection: String? = extras.getString(EXTRA_ATTRIBUTE_SEPARATOR)
val backgroundTypeSelection: WidgetBackgroundType = extras.getSerializable(EXTRA_BACKGROUND_TYPE) as WidgetBackgroundType
val backgroundTypeSelection: WidgetBackgroundType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
extras.getSerializable(EXTRA_BACKGROUND_TYPE, WidgetBackgroundType::class.java)
} else {
@Suppress("DEPRECATION")
extras.getSerializable(EXTRA_BACKGROUND_TYPE) as? WidgetBackgroundType
} ?: WidgetBackgroundType.DAYNIGHT
val textColorSelection: String? = extras.getString(EXTRA_TEXT_COLOR)
if (serverId == null || entitySelection == null) {

View file

@ -5,7 +5,7 @@ import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@ -13,7 +13,6 @@ import android.util.Log
import android.view.View
import android.widget.RemoteViews
import android.widget.Toast
import androidx.core.content.getSystemService
import com.google.android.material.color.DynamicColors
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
@ -25,6 +24,7 @@ import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.database.widget.MediaPlayerControlsWidgetDao
import io.homeassistant.companion.android.database.widget.MediaPlayerControlsWidgetEntity
import io.homeassistant.companion.android.database.widget.WidgetBackgroundType
import io.homeassistant.companion.android.util.hasActiveConnection
import io.homeassistant.companion.android.widgets.BaseWidgetProvider
import kotlinx.coroutines.launch
import java.util.LinkedList
@ -92,7 +92,7 @@ class MediaPlayerControlsWidget : BaseWidgetProvider() {
appWidgetId: Int,
appWidgetManager: AppWidgetManager = AppWidgetManager.getInstance(context)
) {
if (!isConnectionActive(context)) {
if (!context.hasActiveConnection()) {
Log.d(TAG, "Skipping widget update since network connection is not active")
return
}
@ -473,7 +473,12 @@ class MediaPlayerControlsWidget : BaseWidgetProvider() {
val showSeek: Boolean? = extras.getBoolean(EXTRA_SHOW_SEEK)
val showVolume: Boolean? = extras.getBoolean(EXTRA_SHOW_VOLUME)
val showSource: Boolean? = extras.getBoolean(EXTRA_SHOW_SOURCE)
val backgroundType: WidgetBackgroundType = extras.getSerializable(EXTRA_BACKGROUND_TYPE) as WidgetBackgroundType
val backgroundType: WidgetBackgroundType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
extras.getSerializable(EXTRA_BACKGROUND_TYPE, WidgetBackgroundType::class.java)
} else {
@Suppress("DEPRECATION")
extras.getSerializable(EXTRA_BACKGROUND_TYPE) as? WidgetBackgroundType
} ?: WidgetBackgroundType.DAYNIGHT
if (serverId == null || entitySelection == null || showSkip == null || showSeek == null || showVolume == null || showSource == null) {
Log.e(TAG, "Did not receive complete configuration data")
@ -773,10 +778,4 @@ class MediaPlayerControlsWidget : BaseWidgetProvider() {
appWidgetIds.forEach { removeSubscription(it) }
}
}
private fun isConnectionActive(context: Context): Boolean {
val connectivityManager = context.getSystemService<ConnectivityManager>()
val activeNetworkInfo = connectivityManager?.activeNetworkInfo
return activeNetworkInfo?.isConnected ?: false
}
}

View file

@ -8,14 +8,15 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.text.Html.fromHtml
import android.util.Log
import android.util.TypedValue
import android.view.View
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import androidx.core.graphics.toColorInt
import androidx.core.text.HtmlCompat
import com.google.android.material.color.DynamicColors
import dagger.hilt.android.AndroidEntryPoint
import io.homeassistant.companion.android.R
@ -249,7 +250,7 @@ class TemplateWidget : AppWidgetProvider() {
}
setTextViewText(
R.id.widgetTemplateText,
fromHtml(renderedTemplate)
renderedTemplate?.let { HtmlCompat.fromHtml(it, HtmlCompat.FROM_HTML_MODE_LEGACY) }
)
setTextViewTextSize(
R.id.widgetTemplateText,
@ -268,7 +269,12 @@ class TemplateWidget : AppWidgetProvider() {
val serverId = if (extras.containsKey(EXTRA_SERVER_ID)) extras.getInt(EXTRA_SERVER_ID) else null
val template: String? = extras.getString(EXTRA_TEMPLATE)
val textSize: Float = extras.getFloat(EXTRA_TEXT_SIZE)
val backgroundTypeSelection: WidgetBackgroundType = extras.getSerializable(EXTRA_BACKGROUND_TYPE) as WidgetBackgroundType
val backgroundTypeSelection: WidgetBackgroundType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
extras.getSerializable(EXTRA_BACKGROUND_TYPE, WidgetBackgroundType::class.java)
} else {
@Suppress("DEPRECATION")
extras.getSerializable(EXTRA_BACKGROUND_TYPE) as? WidgetBackgroundType
} ?: WidgetBackgroundType.DAYNIGHT
val textColorSelection: String? = extras.getString(EXTRA_TEXT_COLOR)
if (serverId == null || template == null) {

View file

@ -6,7 +6,6 @@ import android.content.ComponentName
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.text.Html.fromHtml
import android.util.Log
import android.view.View
import android.widget.AdapterView
@ -15,6 +14,7 @@ import android.widget.Spinner
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.graphics.toColorInt
import androidx.core.text.HtmlCompat
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope
@ -247,7 +247,7 @@ class TemplateWidgetConfigureActivity : BaseWidgetConfigureActivity() {
enabled = false
}
}
binding.renderedTemplate.text = fromHtml(templateText)
binding.renderedTemplate.text = templateText?.let { HtmlCompat.fromHtml(it, HtmlCompat.FROM_HTML_MODE_LEGACY) }
binding.addButton.isEnabled = enabled && isValidServerId()
}
}

View file

@ -1,6 +1,7 @@
package io.homeassistant.companion.android.common.util
import okhttp3.internal.and
import java.util.Locale
private val HEX_ARRAY = "0123456789ABCDEF".toCharArray()
@ -13,3 +14,6 @@ fun ByteArray.toHexString(): String { // From https://stackoverflow.com/a/985533
}
return String(hexChars)
}
fun String.capitalize(locale: Locale) =
replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() }

View file

@ -25,6 +25,7 @@ import com.mikepenz.iconics.compose.Image
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
import io.homeassistant.companion.android.common.data.integration.Entity
import io.homeassistant.companion.android.common.data.integration.getIcon
import io.homeassistant.companion.android.common.util.capitalize
import io.homeassistant.companion.android.data.SimplifiedEntity
import io.homeassistant.companion.android.theme.WearAppTheme
import io.homeassistant.companion.android.util.stringForDomain