diff --git a/cars/.gitignore b/cars/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/cars/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/cars/build.gradle.kts b/cars/build.gradle.kts new file mode 100644 index 000000000..0fb7ec7d4 --- /dev/null +++ b/cars/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + alias(libs.plugins.android.application) +} + +android { + namespace = "com.example.cars" + compileSdk = libs.versions.compileSdk.get().toInt() + + defaultConfig { + applicationId = "com.example.cars" + minSdk = 24 + targetSdk = libs.versions.targetSdk.get().toInt() + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.car) + implementation(libs.google.android.material) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext.junit) + androidTestImplementation(libs.androidx.test.espresso.core) +} \ No newline at end of file diff --git a/cars/proguard-rules.pro b/cars/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/cars/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/cars/src/main/AndroidManifest.xml b/cars/src/main/AndroidManifest.xml new file mode 100644 index 000000000..0d77fa244 --- /dev/null +++ b/cars/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/cars/src/main/java/com/example/cars/apps/AutomotiveOS.kt b/cars/src/main/java/com/example/cars/apps/AutomotiveOS.kt new file mode 100644 index 000000000..be83f8ab2 --- /dev/null +++ b/cars/src/main/java/com/example/cars/apps/AutomotiveOS.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.cars.apps + +import android.content.Intent +import androidx.car.app.Screen +import androidx.car.app.Session +import com.example.cars.apps.library.MyStartScreen + +// [START android_cars_apps_automotive_os_handle_intents] +class MySession : Session() { + // ... + override fun onCreateScreen(intent: Intent): Screen { + // Handle the intent when the app is being started for the first time + return MyStartScreen(carContext) + } + + override fun onNewIntent(intent: Intent) { + // Handle the intent when the app is already running + } +} +// [END android_cars_apps_automotive_os_handle_intents] diff --git a/cars/src/main/java/com/example/cars/apps/IOT.kt b/cars/src/main/java/com/example/cars/apps/IOT.kt new file mode 100644 index 000000000..0a85c7465 --- /dev/null +++ b/cars/src/main/java/com/example/cars/apps/IOT.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.cars.apps + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.CarIcon +import androidx.car.app.model.GridItem +import androidx.car.app.model.GridTemplate +import androidx.car.app.model.Header +import androidx.car.app.model.ItemList +import androidx.car.app.model.Template +import androidx.core.graphics.drawable.IconCompat +import com.example.cars.R + +class IOTScreen(carContext: CarContext) : Screen(carContext) { + override fun onGetTemplate(): Template { + // [START android_cars_apps_iot_grid_template] + val listBuilder = ItemList.Builder() + val headerBuilder = Header.Builder() + val garageIcon = IconCompat.createWithResource( + carContext, + R.drawable.ic_garage + ) + + listBuilder.addItem( + GridItem.Builder() + .setTitle("Garage door") + .setImage( + CarIcon.Builder(garageIcon).build(), + GridItem.IMAGE_TYPE_ICON + ) + .setOnClickListener { + // Handle user interactions + } + .build() + ) + + listBuilder.addItem( + GridItem.Builder() + .setTitle("Garage lights") + // Show a loading indicator until the status of the device is known + // (call invalidate() when the status is known to refresh the screen) + .setLoading(true) + .build() + ) + + return GridTemplate.Builder() + .setHeader( + headerBuilder.setTitle("Devices") + .setStartHeaderAction(Action.APP_ICON).build() + ) + .setSingleList(listBuilder.build()) + .build() + // [END android_cars_apps_iot_grid_template] + } +} diff --git a/cars/src/main/java/com/example/cars/apps/POI.kt b/cars/src/main/java/com/example/cars/apps/POI.kt new file mode 100644 index 000000000..938924e52 --- /dev/null +++ b/cars/src/main/java/com/example/cars/apps/POI.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.cars.apps + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.PlaceListMapTemplate +import androidx.car.app.model.Template + +class MainScreen(carContext: CarContext) : Screen(carContext) { + override fun onGetTemplate(): Template { + // [START android_cars_apps_poi_refresh_content] + return PlaceListMapTemplate.Builder() + // ... + .setOnContentRefreshListener { + // Execute any desired logic + // ... + // Then call invalidate() so onGetTemplate() is called again + invalidate() + } + .build() + // [END android_cars_apps_poi_refresh_content] + } +} diff --git a/cars/src/main/java/com/example/cars/apps/library/StartScreen.kt b/cars/src/main/java/com/example/cars/apps/library/StartScreen.kt new file mode 100644 index 000000000..ba8986e0d --- /dev/null +++ b/cars/src/main/java/com/example/cars/apps/library/StartScreen.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2026 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.cars.apps.library + +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.Header +import androidx.car.app.model.Pane +import androidx.car.app.model.PaneTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template + +// [START android_cars_apps_library_start_screen] +class MyStartScreen(carContext: CarContext) : Screen(carContext) { + override fun onGetTemplate(): Template { + val row = Row.Builder().setTitle("Hello world!").build() + val pane = Pane.Builder().addRow(row).build() + val header = Header.Builder() + .setStartHeaderAction(Action.APP_ICON) + .build() + return PaneTemplate.Builder(pane) + .setHeader(header) + .build() + } +} +// [END android_cars_apps_library_start_screen] diff --git a/cars/src/main/res/drawable/ic_garage.xml b/cars/src/main/res/drawable/ic_garage.xml new file mode 100644 index 000000000..4744ee3ef --- /dev/null +++ b/cars/src/main/res/drawable/ic_garage.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/cars/src/main/res/drawable/ic_launcher_background.xml b/cars/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..da4cfc866 --- /dev/null +++ b/cars/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cars/src/main/res/drawable/ic_launcher_foreground.xml b/cars/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..9e14c8458 --- /dev/null +++ b/cars/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + diff --git a/cars/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/cars/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..d72381561 --- /dev/null +++ b/cars/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/cars/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/cars/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..d72381561 --- /dev/null +++ b/cars/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/cars/src/main/res/mipmap-hdpi/ic_launcher.webp b/cars/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000..c209e78ec Binary files /dev/null and b/cars/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/cars/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/cars/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000..b2dfe3d1b Binary files /dev/null and b/cars/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/cars/src/main/res/mipmap-mdpi/ic_launcher.webp b/cars/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000..4f0f1d64e Binary files /dev/null and b/cars/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/cars/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/cars/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000..62b611da0 Binary files /dev/null and b/cars/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/cars/src/main/res/mipmap-xhdpi/ic_launcher.webp b/cars/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000..948a3070f Binary files /dev/null and b/cars/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/cars/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/cars/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..1b9a6956b Binary files /dev/null and b/cars/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/cars/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/cars/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000..28d4b77f9 Binary files /dev/null and b/cars/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/cars/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/cars/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9287f5083 Binary files /dev/null and b/cars/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/cars/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/cars/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000..aa7d6427e Binary files /dev/null and b/cars/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/cars/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/cars/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9126ae37c Binary files /dev/null and b/cars/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/cars/src/main/res/values-night/themes.xml b/cars/src/main/res/values-night/themes.xml new file mode 100644 index 000000000..ef64b4724 --- /dev/null +++ b/cars/src/main/res/values-night/themes.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/cars/src/main/res/values/colors.xml b/cars/src/main/res/values/colors.xml new file mode 100644 index 000000000..068b7a9e6 --- /dev/null +++ b/cars/src/main/res/values/colors.xml @@ -0,0 +1,25 @@ + + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + diff --git a/cars/src/main/res/values/strings.xml b/cars/src/main/res/values/strings.xml new file mode 100644 index 000000000..20822c168 --- /dev/null +++ b/cars/src/main/res/values/strings.xml @@ -0,0 +1,19 @@ + + + + Cars Snippets + diff --git a/cars/src/main/res/values/themes.xml b/cars/src/main/res/values/themes.xml new file mode 100644 index 000000000..e3311ad4b --- /dev/null +++ b/cars/src/main/res/values/themes.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b6b5da15f..c1e47c4a9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ androidx-activity-compose = "1.13.0" androidx-appcompat = "1.7.1" androidx-appfunctions = "1.0.0-alpha08" androidx-cameraX = "1.6.0" +androidx-car = "1.7.0" androidx-compose-bom = "2026.03.00" androidx-compose-ui-test = "1.7.0-alpha08" androidx-compose-ui-test-junit4-accessibility = "1.11.0-beta01" @@ -129,6 +130,7 @@ androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = " androidx-camera-compose = { module = "androidx.camera:camera-compose", version.ref = "androidx-cameraX" } androidx-camera-viewfinder-compose = { module = "androidx.camera.viewfinder:viewfinder-compose", version.ref = "androidx-cameraX" } androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidx-cameraX" } +androidx-car = { module = "androidx.car.app:app", version.ref = "androidx-car"} androidx-compose-animation-graphics = { module = "androidx.compose.animation:animation-graphics", version.ref = "compose-latest" } androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidx-compose-bom" } androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "compose-latest" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 9b6c48e5e..4952320ac 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -48,5 +48,6 @@ include( ":playbilling", ":tv", ":contacts", + ":cars", ":installprompt", )