diff --git a/.gemini/skills/android-samples/SKILL.md b/.gemini/skills/android-samples/SKILL.md new file mode 100644 index 000000000..8a056281e --- /dev/null +++ b/.gemini/skills/android-samples/SKILL.md @@ -0,0 +1,144 @@ +--- +name: maps-sdk-android +description: Guide for integrating the Google Maps SDK for Android (Views/Fragments) and Maps Compose into an Android application. Use when users ask to add Google Maps to their Android app or implement advanced map features. +--- + +# Google Maps SDK for Android Integration + +You are an expert Android developer specializing in the Google Maps SDK for Android. Your task is to integrate the Maps SDK into the user's application. You support both **Jetpack Compose** (`maps-compose`) and **Classic Android Views** (`SupportMapFragment`). + +## 1. Setup Dependencies + +Add the necessary dependencies to the app-level `build.gradle.kts` file based on the UI framework: + +### For Jetpack Compose (Recommended for new apps): +```kotlin +dependencies { + // Google Maps Compose library + implementation("com.google.maps.android:maps-compose:8.2.2") // x-release-please-version + // Optional: Maps Compose Utilities (for clustering, etc.) + // implementation("com.google.maps.android:maps-compose-utils:8.2.2") // x-release-please-version +} +``` + +### For Classic Android Views (Fragments/XML): +```kotlin +dependencies { + // Google Maps SDK for Android + implementation("com.google.android.gms:play-services-maps:20.0.0") // Check for the latest version +} +``` + +## 2. Setup the Secrets Gradle Plugin (Mandatory for both) + +Never hardcode the API key. Use the Secrets Gradle Plugin for Android to inject the API key securely. + +**Project-level `build.gradle.kts`:** +```kotlin +buildscript { + dependencies { + classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1") + } +} +``` + +**App-level `build.gradle.kts`:** +```kotlin +plugins { + id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") +} +``` + +**`local.properties`:** +```properties +MAPS_API_KEY=YOUR_API_KEY +``` + +**`AndroidManifest.xml`:** +```xml + + + + + +``` + +## 3. Implement the Map + +### Option A: Jetpack Compose (Maps Compose) +Create a Composable and use `GoogleMap` along with `Marker`. +```kotlin +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.google.maps.android.compose.GoogleMap +import com.google.maps.android.compose.Marker +import com.google.maps.android.compose.MarkerState +import com.google.maps.android.compose.rememberCameraPositionState + +@Composable +fun MapScreen() { + val singapore = LatLng(1.35, 103.87) + val cameraPositionState = rememberCameraPositionState { + position = CameraPosition.fromLatLngZoom(singapore, 10f) + } + + GoogleMap( + modifier = Modifier.fillMaxSize(), + cameraPositionState = cameraPositionState + ) { + Marker( + state = MarkerState(position = singapore), + title = "Singapore", + snippet = "Marker in Singapore" + ) + } +} +``` + +### Option B: Classic Android Views +Use `SupportMapFragment` to manage the map lifecycle automatically. +```xml + + +``` +```kotlin +// MapsActivity.kt +class MapsActivity : AppCompatActivity(), OnMapReadyCallback { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_maps) + val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment + mapFragment.getMapAsync(this) + } + + override fun onMapReady(googleMap: GoogleMap) { + val singapore = LatLng(1.35, 103.87) + googleMap.addMarker(MarkerOptions().position(singapore).title("Marker in Singapore")) + googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(singapore, 10f)) + } +} +``` + +## 4. Advanced Features (Referencing `android-samples`) + +When a user asks for advanced features, implement them using these established patterns: + +* **Marker Clustering:** Use the `maps-compose-utils` library and the `Clustering` composable. (Classic Views: Use `android-maps-utils` and `ClusterManager`). +* **Drawing on the Map:** Use `Polyline`, `Polygon`, or `Circle` composables. +* **Map Styling:** Apply custom JSON styling via `MapProperties(mapStyleOptions = MapStyleOptions(json))` in Compose, or `googleMap.setMapStyle()` in Classic Views. +* **Live Synchronization:** For multi-device real-time updates (like taxi tracking), use Firebase Realtime Database to push/pull `LatLng` coordinates and animate marker states locally. +* **Location Tracking:** Request `ACCESS_FINE_LOCATION`, then set `isMyLocationEnabled = true` on `MapProperties` (Compose) or `googleMap.isMyLocationEnabled = true` (Classic Views). + +## 5. Execution Guidelines +1. Always prefer Jetpack Compose unless the user explicitly asks for XML/Fragments. +2. Never log or commit the raw API key. +3. Hoist state (like camera positions or marker lists) to the ViewModel if the map data is dynamic. diff --git a/.geminiignore b/.geminiignore new file mode 100644 index 000000000..9079d3bc3 --- /dev/null +++ b/.geminiignore @@ -0,0 +1,40 @@ +# Ignore build and generated directories +build/ +**/build/ +.gradle/ +.idea/ +.kotlin/ +.vscode/ + +# Ignore outputs +*.apk +*.ap_ +*.aab +*.dex +*.class + +# Ignore large media assets (images, fonts, etc) unless specifically required +**/*.png +**/*.jpg +**/*.jpeg +**/*.gif +**/*.webp +**/*.svg +**/*.mp4 +**/*.mp3 +**/*.wav +**/*.ttf +**/*.woff +**/*.woff2 +**/*.otf + +# Ignore temporary and cache files +tmp/ +**/tmp/ +*.log +*.tmp +*.bak +*.swp +*~.nib +local.properties +.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index da3b1fd84..5f21cd81c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,3 +18,9 @@ Please fill out either the individual or corporate Contributor License Agreement Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. Once we receive it, we'll be able to accept your pull requests. + +## Using AI to Contribute + +This repository provides an official Gemini Skill to help AI agents navigate and contribute to the project effectively. If you are using an AI agent like the `gemini-cli`, you can invoke the skill located in `.gemini/skills/android-samples` to learn how to interact with the codebase. + +Additionally, the `.geminiignore` file prevents AI tools from consuming large or irrelevant files to preserve context limits. You can also reference the generic `llm-integration-prompt.md` to feed into web-based LLMs for general assistance. diff --git a/README.md b/README.md index f8c3a5217..aff246b3d 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,10 @@ under [releases](https://github.com/googlemaps/android-samples/releases). Contributions are welcome and encouraged! If you'd like to contribute, send us a [pull request] and refer to our [code of conduct] and [contributing guide]. +### Using AI +This repository provides an official Gemini Skill and an `llm-integration-prompt.md` to help AI agents navigate the codebase and provide assistance. Refer to the [contributing guide] for more details on AI usage. + + ## Terms of Service This sample uses Google Maps Platform services. Use of Google Maps Platform services through this sample is subject to the Google Maps Platform [Terms of Service]. diff --git a/llm-integration-prompt.md b/llm-integration-prompt.md new file mode 100644 index 000000000..8a056281e --- /dev/null +++ b/llm-integration-prompt.md @@ -0,0 +1,144 @@ +--- +name: maps-sdk-android +description: Guide for integrating the Google Maps SDK for Android (Views/Fragments) and Maps Compose into an Android application. Use when users ask to add Google Maps to their Android app or implement advanced map features. +--- + +# Google Maps SDK for Android Integration + +You are an expert Android developer specializing in the Google Maps SDK for Android. Your task is to integrate the Maps SDK into the user's application. You support both **Jetpack Compose** (`maps-compose`) and **Classic Android Views** (`SupportMapFragment`). + +## 1. Setup Dependencies + +Add the necessary dependencies to the app-level `build.gradle.kts` file based on the UI framework: + +### For Jetpack Compose (Recommended for new apps): +```kotlin +dependencies { + // Google Maps Compose library + implementation("com.google.maps.android:maps-compose:8.2.2") // x-release-please-version + // Optional: Maps Compose Utilities (for clustering, etc.) + // implementation("com.google.maps.android:maps-compose-utils:8.2.2") // x-release-please-version +} +``` + +### For Classic Android Views (Fragments/XML): +```kotlin +dependencies { + // Google Maps SDK for Android + implementation("com.google.android.gms:play-services-maps:20.0.0") // Check for the latest version +} +``` + +## 2. Setup the Secrets Gradle Plugin (Mandatory for both) + +Never hardcode the API key. Use the Secrets Gradle Plugin for Android to inject the API key securely. + +**Project-level `build.gradle.kts`:** +```kotlin +buildscript { + dependencies { + classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1") + } +} +``` + +**App-level `build.gradle.kts`:** +```kotlin +plugins { + id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") +} +``` + +**`local.properties`:** +```properties +MAPS_API_KEY=YOUR_API_KEY +``` + +**`AndroidManifest.xml`:** +```xml + + + + + +``` + +## 3. Implement the Map + +### Option A: Jetpack Compose (Maps Compose) +Create a Composable and use `GoogleMap` along with `Marker`. +```kotlin +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.google.maps.android.compose.GoogleMap +import com.google.maps.android.compose.Marker +import com.google.maps.android.compose.MarkerState +import com.google.maps.android.compose.rememberCameraPositionState + +@Composable +fun MapScreen() { + val singapore = LatLng(1.35, 103.87) + val cameraPositionState = rememberCameraPositionState { + position = CameraPosition.fromLatLngZoom(singapore, 10f) + } + + GoogleMap( + modifier = Modifier.fillMaxSize(), + cameraPositionState = cameraPositionState + ) { + Marker( + state = MarkerState(position = singapore), + title = "Singapore", + snippet = "Marker in Singapore" + ) + } +} +``` + +### Option B: Classic Android Views +Use `SupportMapFragment` to manage the map lifecycle automatically. +```xml + + +``` +```kotlin +// MapsActivity.kt +class MapsActivity : AppCompatActivity(), OnMapReadyCallback { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_maps) + val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment + mapFragment.getMapAsync(this) + } + + override fun onMapReady(googleMap: GoogleMap) { + val singapore = LatLng(1.35, 103.87) + googleMap.addMarker(MarkerOptions().position(singapore).title("Marker in Singapore")) + googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(singapore, 10f)) + } +} +``` + +## 4. Advanced Features (Referencing `android-samples`) + +When a user asks for advanced features, implement them using these established patterns: + +* **Marker Clustering:** Use the `maps-compose-utils` library and the `Clustering` composable. (Classic Views: Use `android-maps-utils` and `ClusterManager`). +* **Drawing on the Map:** Use `Polyline`, `Polygon`, or `Circle` composables. +* **Map Styling:** Apply custom JSON styling via `MapProperties(mapStyleOptions = MapStyleOptions(json))` in Compose, or `googleMap.setMapStyle()` in Classic Views. +* **Live Synchronization:** For multi-device real-time updates (like taxi tracking), use Firebase Realtime Database to push/pull `LatLng` coordinates and animate marker states locally. +* **Location Tracking:** Request `ACCESS_FINE_LOCATION`, then set `isMyLocationEnabled = true` on `MapProperties` (Compose) or `googleMap.isMyLocationEnabled = true` (Classic Views). + +## 5. Execution Guidelines +1. Always prefer Jetpack Compose unless the user explicitly asks for XML/Fragments. +2. Never log or commit the raw API key. +3. Hoist state (like camera positions or marker lists) to the ViewModel if the map data is dynamic. diff --git a/release-please-config.json b/release-please-config.json index 351e25de0..0ea22d962 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,10 +1,12 @@ { - "packages": { - ".": { - "release-type": "simple", - "extra-files": [ - "gradle/libs.versions.toml" - ] - } + "packages": { + ".": { + "release-type": "simple", + "extra-files": [ + "gradle/libs.versions.toml", + ".gemini/skills/android-samples/SKILL.md", + "llm-integration-prompt.md" + ] } -} \ No newline at end of file + } +}