Android Automotive Module (#3423)

* Creation of Automotive Module and Fix OnboardingActivity parent Activity.

* Adding Manifest Dependencies.

* Fixing ktlint

* Remove unused import.

* Copy Google Services to android automotive

Github actions for PR require this to be set up in order for the build to pass.

* Missing two entries to copy the google-services.json file

* Fixing Build Process.

* Version code +2

We add 2 because the app, wear (+1) and automotive versions need to have different version codes.

* Update +3 per recomendation.

* Code to support transition from Full app to Car App Library.

* Fixing linter.

* More ktlin

/home/runner/work/android/android/app/src/main/java/io/homeassistant/companion/android/BaseActivity.kt:19:1 Needless blank line(s)
/home/runner/work/android/android/app/src/main/java/io/homeassistant/companion/android/BaseActivity.kt:31:95 Unnecessary semicolon
/home/runner/work/android/android/app/src/main/java/io/homeassistant/companion/android/BaseActivity.kt:39:1 Unexpected blank line(s) before "}"
/home/runner/work/android/android/app/src/main/java/io/homeassistant/companion/android/BaseActivity.kt:44:1 First line in a method block should not be empty

* Changes to allow navigate back from / native and feedback from PR.

* Indentation fixes.
This commit is contained in:
googlvalenzuela 2023-03-31 14:54:33 -07:00 committed by GitHub
parent e1f797add7
commit 8a322c624f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 1285 additions and 14 deletions

View file

@ -21,7 +21,7 @@ runs:
run: |
COMMITS=`git rev-list --count HEAD`
TAGS=`git tag | grep -v beta | wc -l`
VC=$(((COMMITS+TAGS) << 1))
VC=$((((COMMITS+TAGS) * 3) << 1))
HASH=`git rev-parse --short HEAD`
if [ "${{inputs.beta}}" = "true" ]; then
VERSION=beta-$VC-$HASH

View file

@ -71,6 +71,7 @@ jobs:
./app/build/outputs/apk/full/release/app-full-release.apk
./app/build/outputs/apk/minimal/release/app-minimal-release.apk
./wear/build/outputs/apk/release/wear-release.apk
./app/build/outputs/apk/automotive/release/automotive-full-release.apk
- name: Deploy to Firebase
env:

View file

@ -28,6 +28,7 @@ jobs:
run: |
cp .github/mock-google-services.json app/google-services.json
cp .github/mock-google-services.json wear/google-services.json
cp .github/mock-google-services.json automotive/google-services.json
- name: Validate ktlint
run: ./gradlew ktlintCheck
@ -55,6 +56,7 @@ jobs:
run: |
cp .github/mock-google-services.json app/google-services.json
cp .github/mock-google-services.json wear/google-services.json
cp .github/mock-google-services.json automotive/google-services.json
- name: Validate Lint
run: ./gradlew lint
@ -94,7 +96,8 @@ jobs:
run: |
cp .github/mock-google-services.json app/google-services.json
cp .github/mock-google-services.json wear/google-services.json
cp .github/mock-google-services.json automotive/google-services.json
- uses: ./.github/actions/create-release-notes
name: Create Release Notes

View file

@ -79,6 +79,7 @@ jobs:
./app/build/outputs/apk/full/release/app-full-release.apk
./app/build/outputs/apk/minimal/release/app-minimal-release.apk
./wear/build/outputs/apk/release/wear-release.apk
./app/build/outputs/apk/automotive/release/automotive-full-release.apk
./app/build/outputs/version_code.txt
- name: Deploy to Firebase

View file

@ -20,6 +20,8 @@ android {
ndkVersion = "21.3.6528147"
useLibrary("android.car")
defaultConfig {
applicationId = "io.homeassistant.companion.android"
minSdk = 21

View file

@ -1,12 +1,16 @@
package io.homeassistant.companion.android.vehicle
import android.car.Car
import android.car.drivingstate.CarUxRestrictionsManager
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.car.app.CarContext
import androidx.car.app.Screen
import androidx.car.app.model.Action
import androidx.car.app.model.ActionStrip
import androidx.car.app.model.CarColor
import androidx.car.app.model.CarIcon
import androidx.car.app.model.ItemList
@ -15,7 +19,9 @@ import androidx.car.app.model.MessageTemplate
import androidx.car.app.model.ParkedOnlyOnClickListener
import androidx.car.app.model.Row
import androidx.car.app.model.Template
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.mikepenz.iconics.IconicsDrawable
@ -72,17 +78,29 @@ class MainVehicleScreen(
private var isLoggedIn: Boolean? = null
private val domains = mutableSetOf<String>()
private var car: Car? = null
private var carRestrictionManager: CarUxRestrictionsManager? = null
private val iDrivingOptimized
get() = car?.let {
(
it.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager
).getCurrentCarUxRestrictions().isRequiresDistractionOptimization()
} ?: false
private val isAutomotive get() = carContext.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
init {
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
isLoggedIn = serverManager.isRegistered() &&
serverManager.authenticationRepository().getSessionState() == SessionState.CONNECTED
serverManager.authenticationRepository()
.getSessionState() == SessionState.CONNECTED
invalidate()
while (isLoggedIn != true) {
delay(1000)
isLoggedIn = serverManager.isRegistered() &&
serverManager.authenticationRepository().getSessionState() == SessionState.CONNECTED
serverManager.authenticationRepository()
.getSessionState() == SessionState.CONNECTED
invalidate()
}
allEntities.collect { entities ->
@ -96,6 +114,19 @@ class MainVehicleScreen(
}
}
}
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onResume(owner: LifecycleOwner) {
registerAutomotiveRestrictionListener()
}
override fun onPause(owner: LifecycleOwner) {
carRestrictionManager?.unregisterListener()
car?.disconnect()
car = null
}
})
}
override fun onGetTemplate(): Template {
@ -108,12 +139,7 @@ class MainVehicleScreen(
.setTitle(carContext.getString(commonR.string.login))
.setOnClickListener(
ParkedOnlyOnClickListener.create {
Log.i(TAG, "Starting login activity")
carContext.startActivity(
Intent(carContext, LaunchActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
)
startNativeActivity()
}
)
.build()
@ -235,6 +261,17 @@ class MainVehicleScreen(
return ListTemplate.Builder().apply {
setTitle(carContext.getString(commonR.string.app_name))
setHeaderAction(Action.APP_ICON)
if (isAutomotive && !iDrivingOptimized) {
setActionStrip(
ActionStrip.Builder().addAction(
Action.Builder()
.setTitle(carContext.getString(commonR.string.aa_launch_native))
.setOnClickListener {
startNativeActivity()
}.build()
).build()
)
}
if (domains.isEmpty()) {
setLoading(true)
} else {
@ -243,4 +280,34 @@ class MainVehicleScreen(
}
}.build()
}
private fun registerAutomotiveRestrictionListener() {
if (carContext.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
Log.i(TAG, "Register for Automotive Restrictions")
car = Car.createCar(carContext)
carRestrictionManager =
car?.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager
var listener =
CarUxRestrictionsManager.OnUxRestrictionsChangedListener { restrictions ->
invalidate()
}
carRestrictionManager?.registerListener(listener)
}
}
private fun startNativeActivity() {
Log.i(TAG, "Starting login activity")
with(carContext) {
startActivity(
Intent(
carContext,
LaunchActivity::class.java
).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
)
if (isAutomotive) {
finishCarApp()
}
}
}
}

View file

@ -1,5 +1,53 @@
package io.homeassistant.companion.android
import android.car.Car
import android.car.drivingstate.CarUxRestrictionsManager
import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
open class BaseActivity : AppCompatActivity()
open class BaseActivity : AppCompatActivity() {
private var car: Car? = null
private var carRestrictionManager: CarUxRestrictionsManager? = null
override fun onResume() {
super.onResume()
registerListener()
}
override fun onStop() {
super.onStop()
carRestrictionManager?.unregisterListener()
car?.disconnect()
car = null
}
private fun registerListener() {
if (packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
car = Car.createCar(this)
carRestrictionManager =
car?.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE) as CarUxRestrictionsManager
var listener =
CarUxRestrictionsManager.OnUxRestrictionsChangedListener { restrictions ->
if (restrictions.isRequiresDistractionOptimization) {
startCarAppActivity()
}
}
carRestrictionManager?.registerListener(listener)
}
}
private fun startCarAppActivity() {
startActivity(
Intent(
this,
Class.forName("androidx.car.app.activity.CarAppActivity")
).addFlags(FLAG_ACTIVITY_NEW_TASK)
)
overridePendingTransition(
androidx.appcompat.R.anim.abc_slide_in_bottom,
androidx.appcompat.R.anim.abc_slide_in_bottom
)
}
}

View file

@ -5,10 +5,10 @@ import android.os.Bundle
import android.view.KeyEvent
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.commit
import dagger.hilt.android.AndroidEntryPoint
import io.homeassistant.companion.android.BaseActivity
import io.homeassistant.companion.android.BuildConfig
import io.homeassistant.companion.android.R
import io.homeassistant.companion.android.onboarding.authentication.AuthenticationFragment
@ -17,7 +17,7 @@ import io.homeassistant.companion.android.onboarding.manual.ManualSetupFragment
import io.homeassistant.companion.android.onboarding.welcome.WelcomeFragment
@AndroidEntryPoint
class OnboardingActivity : AppCompatActivity() {
class OnboardingActivity : BaseActivity() {
companion object {
private const val AUTHENTICATION_FRAGMENT = "authentication_fragment"

228
automotive/build.gradle.kts Normal file
View file

@ -0,0 +1,228 @@
import com.github.triplet.gradle.androidpublisher.ResolutionStrategy
import com.google.gms.googleservices.GoogleServicesPlugin.GoogleServicesPluginConfig
plugins {
id("com.android.application")
id("kotlin-android")
id("kotlin-kapt")
id("kotlin-parcelize")
id("com.google.firebase.appdistribution")
id("com.github.triplet.play")
id("com.google.gms.google-services")
kotlin("kapt")
id("dagger.hilt.android.plugin")
}
android {
namespace = "io.homeassistant.companion.android"
compileSdk = 33
ndkVersion = "21.3.6528147"
useLibrary("android.car")
defaultConfig {
applicationId = "io.homeassistant.companion.android"
minSdk = 29
targetSdk = 33
versionName = System.getenv("VERSION") ?: "LOCAL"
// We add 2 because the app, wear (+1) and automotive versions need to have different version codes.
versionCode = (System.getenv("VERSION_CODE")?.toIntOrNull() ?: 1) + 3
manifestPlaceholders["sentryRelease"] = "$applicationId@$versionName"
manifestPlaceholders["sentryDsn"] = System.getenv("SENTRY_DSN") ?: ""
bundle {
language {
enableSplit = false
}
}
}
sourceSets {
getByName("main") {
java {
srcDirs("../app/src/main/java", "../app/src/full/java")
}
res {
srcDirs("../app/src/main/res", "../app/src/full/res")
}
manifest.srcFile("src/main/AndroidManifest.xml")
}
}
buildFeatures {
viewBinding = true
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.2"
}
kotlinOptions {
jvmTarget = "1.8"
}
compileOptions {
sourceCompatibility(JavaVersion.VERSION_11)
targetCompatibility(JavaVersion.VERSION_11)
}
signingConfigs {
create("release") {
storeFile = file(System.getenv("KEYSTORE_PATH") ?: "release_keystore.keystore")
storePassword = System.getenv("KEYSTORE_PASSWORD") ?: ""
keyAlias = System.getenv("KEYSTORE_ALIAS") ?: ""
keyPassword = System.getenv("KEYSTORE_ALIAS_PASSWORD") ?: ""
enableV1Signing = true
enableV2Signing = true
}
}
buildTypes {
named("debug").configure {
applicationIdSuffix = ".debug"
}
named("release").configure {
isDebuggable = false
isJniDebuggable = false
signingConfig = signingConfigs.getByName("release")
}
}
flavorDimensions.add("version")
productFlavors {
create("minimal") {
applicationIdSuffix = ".minimal"
versionNameSuffix = "-minimal"
}
create("full") {
applicationIdSuffix = ""
versionNameSuffix = "-full"
}
// Generate a list of application ids into BuildConfig
val values = productFlavors.joinToString {
"\"${it.applicationId ?: defaultConfig.applicationId}${it.applicationIdSuffix}\""
}
defaultConfig.buildConfigField("String[]", "APPLICATION_IDS", "{$values}")
}
playConfigs {
register("minimal") {
enabled.set(false)
}
}
testOptions {
unitTests.isReturnDefaultValues = true
}
tasks.withType<Test>().configureEach {
useJUnitPlatform {
includeEngines("spek2")
}
}
lint {
abortOnError = false
disable += "MissingTranslation"
}
kapt {
correctErrorTypes = true
}
}
play {
serviceAccountCredentials.set(file("playStorePublishServiceCredentialsFile.json"))
track.set("internal")
resolutionStrategy.set(ResolutionStrategy.IGNORE)
// We will depend on the wear commit.
commit.set(false)
}
dependencies {
implementation(project(":common"))
implementation("com.github.Dimezis:BlurView:version-1.6.6")
implementation("org.altbeacon:android-beacon-library:2.19.5")
implementation("com.maltaisn:icondialog:3.3.0")
implementation("com.maltaisn:iconpack-community-material:5.3.45")
implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.10")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.10")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
"fullImplementation"("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4")
implementation("com.google.dagger:hilt-android:2.45")
kapt("com.google.dagger:hilt-android-compiler:2.45")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.recyclerview:recyclerview:1.2.1")
implementation("androidx.preference:preference-ktx:1.2.0")
implementation("com.google.android.material:material:1.8.0")
implementation("androidx.fragment:fragment-ktx:1.5.5")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.5")
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation("com.squareup.picasso:picasso:2.8")
implementation("com.google.android.gms:play-services-location:21.0.1")
implementation("com.google.android.gms:play-services-home:16.0.0")
implementation("com.google.android.gms:play-services-threadnetwork:16.0.0-beta02")
implementation(platform("com.google.firebase:firebase-bom:31.2.2"))
implementation("com.google.firebase:firebase-messaging")
implementation("io.sentry:sentry-android:6.14.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4")
implementation("com.google.android.gms:play-services-wearable:18.0.0")
implementation("androidx.wear:wear-remote-interactions:1.0.0")
implementation("androidx.biometric:biometric:1.1.0")
implementation("androidx.webkit:webkit:1.6.0")
implementation("com.google.android.exoplayer:exoplayer-core:2.18.2")
implementation("com.google.android.exoplayer:exoplayer-hls:2.18.2")
implementation("com.google.android.exoplayer:exoplayer-ui:2.18.2")
implementation("com.google.android.exoplayer:extension-cronet:2.18.2")
"minimalImplementation"("com.google.android.exoplayer:extension-cronet:2.18.2") {
exclude(group = "com.google.android.gms", module = "play-services-cronet")
}
"minimalImplementation"("org.chromium.net:cronet-embedded:108.5359.79")
implementation(platform("androidx.compose:compose-bom:2023.01.00"))
implementation("androidx.compose.animation:animation")
implementation("androidx.compose.compiler:compiler:1.4.2")
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.material:material")
implementation("androidx.compose.material:material-icons-core")
implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.compose.runtime:runtime")
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-tooling")
implementation("androidx.activity:activity-compose:1.6.1")
implementation("androidx.navigation:navigation-compose:2.5.3")
implementation("com.google.accompanist:accompanist-themeadapter-material:0.28.0")
implementation("com.mikepenz:iconics-core:5.4.0")
implementation("com.mikepenz:iconics-compose:5.4.0")
implementation("com.mikepenz:community-material-typeface:7.0.96.0-kotlin@aar")
implementation("org.burnoutcrew.composereorderable:reorderable:0.9.6")
implementation("com.github.AppDevNext:ChangeLog:3.4")
implementation("androidx.car.app:app:1.3.0-rc01")
implementation("androidx.car.app:app-automotive:1.3.0-rc01")
}
// Disable to fix memory leak and be compatible with the configuration cache.
configure<GoogleServicesPluginConfig> {
disableVersionCheck = true
}

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="com.google.android.gms.threadnetwork" />
<application
android:name="io.homeassistant.companion.android.HomeAssistantApplication" >
<meta-data android:name="io.sentry.auto-init" android:value="false" />
<meta-data android:name="io.sentry.release" android:value="${sentryRelease}" />
<meta-data android:name="io.sentry.dsn" android:value="${sentryDsn}" />
<activity
android:name=".matter.MatterCommissioningActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:theme="@style/Theme.HomeAssistant.Config">
<intent-filter>
<action android:name="com.google.android.gms.home.matter.ACTION_COMMISSION_DEVICE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<receiver android:name=".location.HighAccuracyLocationReceiver"
android:enabled="true"
android:exported="true" />
<service
android:name=".notifications.FirebaseCloudMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service
android:name=".location.HighAccuracyLocationService"
android:enabled="true"
android:exported="true"/>
<service
android:name=".matter.MatterCommissioningService"
android:exported="true" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorPrimary" />
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
<meta-data
android:name="com.android.automotive"
android:resource="@xml/automotive_app_desc"/>
<service
android:name=".vehicle.HaCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.IOT"/>
</intent-filter>
</service>
<activity
android:name="androidx.car.app.activity.CarAppActivity"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:exported="true"
android:launchMode="singleTask"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="distractionOptimized" android:value="true"/>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,838 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="androidx.wear.remote.interactions" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions"/>
<uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.nfc" android:required="false"/>
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
<uses-feature android:name="android.hardware.sensor" android:required="false"/>
<uses-feature android:name="android.hardware.microphone" android:required="false" />
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.type.automotive" android:required="true" />
<uses-feature android:name="android.software.car.templates_host" android:required="true" />
<application
android:name="io.homeassistant.companion.android.HomeAssistantApplication"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/backup_rules_android12"
android:icon="@mipmap/ic_launcher"
android:banner="@mipmap/ic_banner"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.HomeAssistant"
android:networkSecurityConfig="@xml/network_security_config"
android:enableOnBackInvokedCallback="true"
android:localeConfig="@xml/locales_config"
tools:ignore="GoogleAppIndexingWarning"
tools:targetApi="tiramisu">
<!-- Start things like SensorWorker on device boot -->
<receiver android:name=".websocket.WebsocketBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
<action android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
</intent-filter>
</receiver>
<receiver android:name=".sensors.SensorReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
<action android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
<action android:name="io.homeassistant.companion.android.UPDATE_SENSORS" />
</intent-filter>
</receiver>
<receiver android:name=".widgets.button.ButtonWidget" android:label="@string/widget_button_image_description"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="io.homeassistant.companion.android.widgets.ButtonWidget.CALL_SERVICE" />
<action android:name="io.homeassistant.companion.android.widgets.ButtonWidget.CALL_SERVICE_AUTH" />
<action android:name="io.homeassistant.companion.android.widgets.ButtonWidget.RECEIVE_DATA" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/button_widget_info" />
</receiver>
<receiver android:name=".widgets.camera.CameraWidget" android:label="@string/widget_camera_description"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="io.homeassistant.companion.android.widgets.camera.CameraWidget.RECEIVE_DATA" />
<action android:name="io.homeassistant.companion.android.widgets.camera.CameraWidget.UPDATE_IMAGE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/camera_widget_info" />
</receiver>
<receiver android:name=".widgets.entity.EntityWidget" android:label="@string/widget_static_image_description"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="io.homeassistant.companion.android.widgets.StaticWidget.RECEIVE_DATA" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/entity_widget_info" />
</receiver>
<receiver android:name=".widgets.mediaplayer.MediaPlayerControlsWidget" android:label="@string/widget_media_player_description"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="io.homeassistant.companion.android.widgets.media_player_controls.MediaPlayerControlsWidget.RECEIVE_DATA" />
<action android:name="io.homeassistant.companion.android.widgets.media_player_controls.MediaPlayerControlsWidget.UPDATE_MEDIA_IMAGE" />
<action android:name="io.homeassistant.companion.android.widgets.media_player_controls.MediaPlayerControlsWidget.CALL_PREV_TRACK" />
<action android:name="io.homeassistant.companion.android.widgets.media_player_controls.MediaPlayerControlsWidget.CALL_REWIND" />
<action android:name="io.homeassistant.companion.android.widgets.media_player_controls.MediaPlayerControlsWidget.CALL_PLAYPAUSE" />
<action android:name="io.homeassistant.companion.android.widgets.media_player_controls.MediaPlayerControlsWidget.CALL_FASTFORWARD" />
<action android:name="io.homeassistant.companion.android.widgets.media_player_controls.MediaPlayerControlsWidget.CALL_NEXT_TRACK" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/media_player_control_widget_info" />
</receiver>
<receiver android:name=".widgets.template.TemplateWidget" android:label="@string/template_widget"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
<action android:name="io.homeassistant.companion.android.background.REQUEST_SENSORS_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="io.homeassistant.companion.android.widgets.template.TemplateWidget.RECEIVE_DATA" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/template_widget_info" />
</receiver>
<activity android:name=".widgets.button.ButtonWidgetConfigureActivity"
android:configChanges="orientation|screenSize"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<activity android:name=".widgets.common.WidgetAuthenticationActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:theme="@style/Theme.Transparent">
</activity>
<activity android:name=".widgets.camera.CameraWidgetConfigureActivity"
android:configChanges="orientation|screenSize"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<activity android:name=".widgets.entity.EntityWidgetConfigureActivity"
android:configChanges="orientation|screenSize"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<activity android:name=".widgets.mediaplayer.MediaPlayerControlsWidgetConfigureActivity"
android:configChanges="orientation|screenSize"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<activity android:name=".widgets.template.TemplateWidgetConfigureActivity"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<service android:name=".sensors.NotificationSensorManager"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService"/>
</intent-filter>
</service>
<service android:name=".controls.HaControlsProviderService"
android:permission="android.permission.BIND_CONTROLS"
android:exported="true">
<intent-filter>
<action android:name="android.service.controls.ControlsProviderService"/>
</intent-filter>
</service>
<receiver
android:name=".sensors.LocationSensorManager"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="io.homeassistant.companion.android.background.REQUEST_ACCURATE_UPDATE" />
</intent-filter>
</receiver>
<receiver
android:name=".sensors.ActivitySensorManager"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="io.homeassistant.companion.android.background.REQUEST_ACTIVITY_UPDATES" />
</intent-filter>
</receiver>
<activity android:name=".launch.LaunchActivity"
android:exported="true"
android:theme="@style/Theme.LaunchScreen">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="homeassistant"
android:host="navigate" />
</intent-filter>
</activity>
<activity android:name=".launch.my.MyActivity"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="my.home-assistant.io"
android:pathPrefix="/redirect/"/>
</intent-filter>
</activity>
<activity
android:name=".onboarding.OnboardingActivity"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden|navigation"
android:theme="@style/Theme.HomeAssistant.Config" />
<activity
android:name=".settings.wear.SettingsWearActivity"
android:parentActivityName=".settings.SettingsActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:theme="@style/Theme.HomeAssistant.Config">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="homeassistant"
android:host="wear-phone-signin" />
</intent-filter>
</activity>
<activity
android:name=".settings.wear.views.SettingsWearMainView"
android:parentActivityName=".settings.SettingsActivity"
android:configChanges="orientation|screenSize"
android:theme="@style/Theme.HomeAssistant.Config" />
<service android:name=".onboarding.WearOnboardingListener"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data android:scheme="wear" android:host="*"
android:path="/request_home_assistant_instance" />
</intent-filter>
</service>
<activity
android:name=".webview.WebViewActivity"
android:supportsPictureInPicture="true"
android:resizeableActivity="true"
android:exported="false"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation" />
<activity
android:name=".settings.SettingsActivity"
android:parentActivityName=".webview.WebViewActivity"
android:exported="false"
android:configChanges="orientation|screenSize"
android:theme="@style/Theme.HomeAssistant.Config"/>
<activity
android:name=".nfc.TagReaderActivity"
android:label="@string/tag_reader_title"
android:exported="true">
<tools:validation testUrl="https://www.home-assistant.io/tag/123e4567-e89b-12d3-a456-426614174000" />
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="www.home-assistant.io"
android:pathPrefix="/tag/" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="www.home-assistant.io"
android:pathPrefix="/tag/" />
</intent-filter>
</activity>
<activity
android:name=".nfc.NfcSetupActivity"
android:exported="false"
android:label="@string/nfc_title_nfc_setup"
android:theme="@style/Theme.HomeAssistant.Config" />
<activity android:name=".share.ShareActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/*" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
<service
android:name=".qs.Tile1Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_1"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile2Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_2"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile3Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_3"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile4Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_4"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile5Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_5"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile6Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_6"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile7Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_7"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile8Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_8"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile9Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_9"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile10Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_10"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile11Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_11"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile12Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_12"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile13Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_13"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile14Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_14"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile15Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_15"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile16Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_16"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile17Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_17"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile18Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_18"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile19Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_19"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile20Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_20"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile21Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_21"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile22Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_22"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile23Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_23"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile24Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_24"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile25Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_25"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile26Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_26"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile27Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_27"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile28Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_28"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile29Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_29"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile30Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_30"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile31Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_31"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile32Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_32"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile33Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_33"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile34Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_34"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile35Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_35"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile36Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_36"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile37Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_37"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile38Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_38"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile39Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_39"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name=".qs.Tile40Service"
android:icon="@drawable/ic_stat_ic_notification"
android:label="@string/tile_40"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:enabled="false"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
android:enabled="false"
android:exported="false">
<meta-data
android:name="autoStoreLocales"
android:value="true" />
</service>
<receiver
android:name=".notifications.NotificationActionReceiver"
android:enabled="true"
android:exported="true" />
<receiver
android:name=".notifications.NotificationDeleteReceiver"
android:enabled="true"
android:exported="true" />
</application>
</manifest>

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="aa_app_not_logged_in">Not logged in</string>
<string name="aa_launch_native">Native mode</string>
<string name="aa_navigation">Navigation</string>
<string name="aa_no_entities_with_locations">No entities with locations found.</string>
<string name="aa_change_server">Change server</string>

View file

@ -1,6 +1,6 @@
import org.gradle.kotlin.dsl.support.serviceOf
include(":common", ":app", ":wear")
include(":common", ":app", ":wear", ":automotive")
rootProject.name = "home-assistant-android"