Skip to content

Commit

Permalink
SDK 12.1.0
Browse files Browse the repository at this point in the history
[SDK-#] В пример Android Auto добавлен CustomRenderer для демонстрации отрисовки поверх карты
  • Loading branch information
v.lazin authored and Sameri11 committed Oct 2, 2024
1 parent e08daec commit 30a4a74
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 13 deletions.
82 changes: 82 additions & 0 deletions app/src/main/java/ru/dgis/sdk/demo/car/CustomRenderer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package ru.dgis.sdk.demo.car

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.Build
import android.view.Surface
import androidx.annotation.RequiresApi

/*
A sample renderer demonstrating drawing capabilities on a surface provided by AndroidAutoMapSession.
This renderer draws a circle with a black background and a number inside, which increments every second.
Refer to MapSession from this demo for details on how to use this renderer.
*/
class CustomRenderer {
private var renderThread: RenderThread? = null

fun start(surface: Surface) {
renderThread = RenderThread(surface)
renderThread?.start()
}

fun stop() {
renderThread?.interrupt()
renderThread?.join()
renderThread = null
}

private class RenderThread(private val surface: Surface) : Thread() {
private val renderIntervalMs = 1000L

@RequiresApi(Build.VERSION_CODES.M)
override fun run() {
var value = 0

while (!isInterrupted) {
var canvas: Canvas? = null
try {
canvas = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
surface.lockHardwareCanvas()
} else {
surface.lockCanvas(null)
}
draw(value++, canvas)
} catch (e: Exception) {
e.printStackTrace()
} finally {
if (canvas != null) {
surface.unlockCanvasAndPost(canvas)
}
}

try {
sleep(renderIntervalMs)
} catch (e: InterruptedException) {
break
}
}
}

private fun draw(value: Int, canvas: Canvas) {
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = Color.BLACK
style = Paint.Style.FILL
}

// Draw a black circle
val centerX = 100f
val centerY = 100f
val radius = 50f
canvas.drawCircle(centerX, centerY, radius, paint)

// Draw the white text inside the circle
paint.apply {
color = Color.WHITE
textSize = 30f
textAlign = Paint.Align.CENTER
}
canvas.drawText("$value", centerX, centerY + paint.textSize / 3, paint)
}
}
}
33 changes: 33 additions & 0 deletions app/src/main/java/ru/dgis/sdk/demo/car/MainScreen.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
package ru.dgis.sdk.demo.car

import androidx.annotation.DrawableRes
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.CarIcon
import androidx.car.app.model.Template
import androidx.car.app.navigation.model.NavigationTemplate
import androidx.core.graphics.drawable.IconCompat
import ru.dgis.sdk.demo.R
import ru.dgis.sdk.map.Map

class MainScreen(carContext: CarContext) : Screen(carContext) {
private var model: MainScreenModel? = null

private fun buildCarIcon(@DrawableRes id: Int): CarIcon {
return CarIcon.Builder(IconCompat.createWithResource(carContext, id)).build()
}

fun setMap(map: Map) {
model = MainScreenModel(map)
}

override fun onGetTemplate(): Template {
val zoomInAction = Action.Builder()
.setIcon(buildCarIcon(R.drawable.ic_zoom_in))
.setOnClickListener { model?.zoomIn() }
.build()

val zoomOutAction = Action.Builder()
.setIcon(buildCarIcon(R.drawable.ic_zoom_out))
.setOnClickListener { model?.zoomOut() }
.build()

val myLocationAction = Action.Builder()
.setIcon(buildCarIcon(R.drawable.ic_nav_point))
.setOnClickListener { model?.recenter() }
.build()

return NavigationTemplate.Builder()
.setActionStrip(
ActionStrip.Builder()
Expand All @@ -18,6 +48,9 @@ class MainScreen(carContext: CarContext) : Screen(carContext) {
.setMapActionStrip(
ActionStrip.Builder()
.addAction(Action.PAN)
.addAction(zoomInAction)
.addAction(zoomOutAction)
.addAction(myLocationAction)
.build()
)
.build()
Expand Down
25 changes: 25 additions & 0 deletions app/src/main/java/ru/dgis/sdk/demo/car/MainScreenModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ru.dgis.sdk.demo.car

import ru.dgis.sdk.map.CameraBehaviour
import ru.dgis.sdk.map.FollowPosition
import ru.dgis.sdk.map.Map
import ru.dgis.sdk.map.ZoomControlButton
import ru.dgis.sdk.map.ZoomControlModel

class MainScreenModel(private val map: Map) {
private val zoomControlModel = ZoomControlModel(map)

fun zoomIn() {
zoomControlModel.setPressed(ZoomControlButton.ZOOM_IN, true)
zoomControlModel.setPressed(ZoomControlButton.ZOOM_IN, false)
}

fun zoomOut() {
zoomControlModel.setPressed(ZoomControlButton.ZOOM_OUT, true)
zoomControlModel.setPressed(ZoomControlButton.ZOOM_OUT, false)
}

fun recenter() {
map.camera.setBehaviour(CameraBehaviour(position = FollowPosition()))
}
}
17 changes: 16 additions & 1 deletion app/src/main/java/ru/dgis/sdk/demo/car/MapService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,23 @@ package ru.dgis.sdk.demo.car
import androidx.car.app.CarAppService
import androidx.car.app.Session
import androidx.car.app.validation.HostValidator
import ru.dgis.sdk.DGis
import ru.dgis.sdk.map.DgisSource.Companion.createDgisSource
import ru.dgis.sdk.map.DgisSourceWorkingMode
import ru.dgis.sdk.map.MapOptions
import ru.dgis.sdk.map.MyLocationMapObjectSource

class MapService : CarAppService() {

private fun createMapOptions(): MapOptions {
return MapOptions().apply {
sources = listOf(
createDgisSource(DGis.context(), DgisSourceWorkingMode.HYBRID_ONLINE_FIRST),
MyLocationMapObjectSource(DGis.context())
)
}
}

override fun createHostValidator(): HostValidator {
// Avoid using ALLOW_ALL_HOSTS_VALIDATOR in production as it is insecure.
// Refer to the Android Auto documentation for proper security practices.
Expand All @@ -18,6 +33,6 @@ class MapService : CarAppService() {
// only when certain activity/fragment/etc opened, and it is not created in Application's onCreate,
// ru.dgis.sdk.Context should be created here in onCreateSession or somewhere earlier.
override fun onCreateSession(): Session {
return MapSession()
return MapSession(createMapOptions())
}
}
49 changes: 38 additions & 11 deletions app/src/main/java/ru/dgis/sdk/demo/car/MapSession.kt
Original file line number Diff line number Diff line change
@@ -1,38 +1,65 @@
package ru.dgis.sdk.demo.car

import android.content.Intent
import android.view.Gravity
import android.view.Surface
import androidx.car.app.AppManager
import androidx.car.app.CarToast
import androidx.car.app.Screen
import ru.dgis.sdk.Future
import ru.dgis.sdk.androidauto.AndroidAutoMapSession
import ru.dgis.sdk.androidauto.CopyrightMargins
import ru.dgis.sdk.androidauto.CopyrightPosition
import ru.dgis.sdk.map.Map
import ru.dgis.sdk.map.MapOptions
import ru.dgis.sdk.map.RenderedObjectInfo
import ru.dgis.sdk.map.ScreenPoint

class MapSession : AndroidAutoMapSession(MapOptions()) {
class MapSession(mapOptions: MapOptions) : AndroidAutoMapSession(mapOptions) {
private val mainScreen = MainScreen(carContext)
private var map: Map? = null
private var customRenderer = CustomRenderer()
private var getRenderedObjectFuture: Future<List<RenderedObjectInfo>>? = null

private fun showToast(message: String) {
carContext.getCarService(AppManager::class.java)
.showToast(message, CarToast.LENGTH_SHORT)
carContext.getCarService(AppManager::class.java).showToast(message, CarToast.LENGTH_SHORT)
}

override fun onCreateScreen(intent: Intent): Screen {
return MainScreen(carContext)
return mainScreen
}

override fun onSurfaceAvailable(surface: Surface, width: Int, height: Int) {
customRenderer.start(surface)
}

override fun onSurfaceClicked(x: Float, y: Float) {
getRenderedObjectFuture = map?.getRenderedObjects(centerPoint = ScreenPoint(x = x, y = y))?.apply {
onResult {
val objectInfo = it.firstOrNull()
showToast("$objectInfo")
}
}
}

override fun onSurfaceDestroyed(surface: Surface) {
customRenderer.stop()
}

override fun onMapReady(map: Map) {
this.map = map

mainScreen.setMap(map)

setCopyrightPosition(
CopyrightPosition(
gravity = Gravity.BOTTOM or Gravity.START,
margins = CopyrightMargins(left = 20, bottom = 20)
)
)
}

override fun onMapReadyException(exception: Exception) {
exception.message?.let(::showToast)
}

override fun onMapClicked(x: Float, y: Float) {
map?.getRenderedObjects(centerPoint = ScreenPoint(x = x, y = y))?.onResult {
val objectInfo = it.firstOrNull()
showToast("$objectInfo")
}
}
}
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_zoom_in.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#fff"
android:fillType="nonZero"
android:pathData="M13,11h3v2h-3v3h-2v-3H8v-2h3V8h2v3z" />
</vector>
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_zoom_out.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#fff"
android:fillType="nonZero"
android:pathData="M8,11h8v2H8z" />
</vector>
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ taskTree = "2.1.1"
undercouch-download = "5.4.0"
ktlint = "11.5.0"

dgis-sdk = "12.0.0"
dgis-sdk = "12.1.0"

appcompat = "1.6.1"
constraintlayout = "2.1.4"
Expand Down

0 comments on commit 30a4a74

Please sign in to comment.