mirror of
https://github.com/home-assistant/android
synced 2024-10-04 15:19:30 +00:00
Update/replace deprecations in app module (#3661)
This commit is contained in:
parent
33dfc69949
commit
bc103636db
|
@ -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())
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -162,6 +162,7 @@ class GeocodeSensorManager : SensorManager {
|
|||
)
|
||||
}
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
getFromLocation(latitude, longitude, maxResults).orEmpty()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 }) {
|
||||
|
|
|
@ -32,7 +32,7 @@ class SensorWorker(
|
|||
.build()
|
||||
|
||||
WorkManager.getInstance(context)
|
||||
.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, sensorWorker)
|
||||
.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, sensorWorker)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ class ManageControlsSettingsFragment : Fragment() {
|
|||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -28,6 +28,7 @@ class NotificationChannelFragment : Fragment() {
|
|||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
},
|
||||
|
|
|
@ -41,6 +41,7 @@ class ManageTilesFragment : Fragment() {
|
|||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 -> {
|
||||
|
|
|
@ -28,6 +28,7 @@ class SensorUpdateFrequencyFragment : Fragment() {
|
|||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ class ManageShortcutsSettingsFragment : Fragment() {
|
|||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ class SsidFragment : Fragment() {
|
|||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ class WebsocketSettingFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ class ManageWidgetsSettingsFragment : Fragment() {
|
|||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
|
||||
|
|
|
@ -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() &&
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,6 @@ object DataUriDownloadManager {
|
|||
.notify(url.hashCode(), notification.build())
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private suspend fun writeDataUriToFile(
|
||||
context: Context,
|
||||
url: String,
|
||||
|
|
|
@ -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 ->
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue