Skip to content

Commit

Permalink
Allow for downstream upgrades
Browse files Browse the repository at this point in the history
  • Loading branch information
kmadsen committed Sep 21, 2022
1 parent fd2dd92 commit 955f14c
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 12 deletions.
7 changes: 5 additions & 2 deletions android-auto-app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ androidExtensions {
dependencies {
implementation(project(":extension-androidauto"))
implementation(project(":sdk"))
implementation(Dependencies.googleCarAppLibrary)
implementation(Dependencies.kotlin)

// Upgrade the google car library to demonstrate adopting new apis.
implementation("androidx.car.app:app:1.3.0-beta01")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.1")
// implementation(Dependencies.kotlin)
implementation(Dependencies.androidxAppCompat)
implementation(Dependencies.androidxCoreKtx)
implementation(Dependencies.googleMaterialDesign)
Expand Down
2 changes: 1 addition & 1 deletion android-auto-app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
tools:ignore="MetadataTagInsideApplicationTag" />
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"
android:value="5"
tools:ignore="MetadataTagInsideApplicationTag" />

<service
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
package com.mapbox.maps.testapp.auto.app

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.mapbox.maps.testapp.auto.R
import com.mapbox.maps.testapp.auto.service.MapboxCarAppService
import kotlinx.android.synthetic.main.activity_main.*


class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

switchButton.setOnCheckedChangeListener { _, isChecked ->
if (MapboxCarAppService.enableCustomCallback != isChecked) {
Toast.makeText(
this,
"Custom setting changed please reconnect to the Android Auto",
Toast.LENGTH_LONG)
.show()
}
MapboxCarAppService.enableCustomCallback = isChecked
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.mapbox.maps.testapp.auto.custom

import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.content.res.Configuration
import androidx.car.app.AppManager
import androidx.car.app.Screen
import androidx.car.app.ScreenManager
import androidx.car.app.Session
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.mapbox.maps.MapInitOptions
import com.mapbox.maps.MapboxExperimental
import com.mapbox.maps.extension.androidauto.MapboxCarMap
import com.mapbox.maps.extension.androidauto.mapboxMapInstaller
import com.mapbox.maps.logI
import com.mapbox.maps.testapp.auto.car.CarAnimationThreadController
import com.mapbox.maps.testapp.auto.car.CarMapShowcase
import com.mapbox.maps.testapp.auto.car.CarMapWidgets
import com.mapbox.maps.testapp.auto.car.MapScreen
import com.mapbox.maps.testapp.auto.car.RequestPermissionScreen

/**
* Session class for the Mapbox Map sample app for Android Auto.
*/
@OptIn(MapboxExperimental::class)
class CustomMapSession : Session() {

private val carAnimationThreadController = CarAnimationThreadController()
private val carMapWidgets = CarMapWidgets()
private val carMapShowcase = CarMapShowcase()
private val mapboxCarMap = MapboxCarMap()

init {
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
val mapInitOptions = MapInitOptions(carContext)
mapboxCarMap.registerObserver(carAnimationThreadController)
mapboxCarMap.registerObserver(carMapWidgets)
mapboxCarMap.registerObserver(carMapShowcase)

val handle = mapboxCarMap.setupWithCustomCallback(carContext, mapInitOptions)
carContext.getCarService(AppManager::class.java)
.setSurfaceCallback(object : CustomSurfaceCallback(handle) {
override fun onClick(x: Float, y: Float) {
super.onClick(x, y)
logI("CustomMapSession", "onClick $x $y")
}
})
}

override fun onDestroy(owner: LifecycleOwner) {
mapboxCarMap.unregisterObserver(carMapShowcase)
mapboxCarMap.unregisterObserver(carMapWidgets)
mapboxCarMap.unregisterObserver(carAnimationThreadController)
}
})
}

override fun onCreateScreen(intent: Intent): Screen {
// The onCreate is guaranteed to be called before onCreateScreen. You can pass the
// mapboxCarMap to other screens. Each screen can register and unregister observers.
// This allows you to scope behaviors to sessions, screens, or events.
val mapScreen = MapScreen(mapboxCarMap)

return if (carContext.checkSelfPermission(ACCESS_FINE_LOCATION) != PERMISSION_GRANTED) {
carContext.getCarService(ScreenManager::class.java)
.push(mapScreen)
RequestPermissionScreen(carContext)
} else mapScreen
}

override fun onCarConfigurationChanged(newConfiguration: Configuration) {
carMapShowcase.loadMapStyle(carContext)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.mapbox.maps.testapp.auto.custom

import android.graphics.Rect
import androidx.car.app.SurfaceCallback
import androidx.car.app.SurfaceContainer
import com.mapbox.maps.MapboxExperimental
import com.mapbox.maps.extension.androidauto.CarMapSurfaceOwner

@OptIn(MapboxExperimental::class)
abstract class CustomSurfaceCallback constructor(
private val carMapSurfaceOwner: CarMapSurfaceOwner
) : SurfaceCallback {

override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) =
carMapSurfaceOwner.onSurfaceAvailable(surfaceContainer)

override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) =
carMapSurfaceOwner.onSurfaceDestroyed(surfaceContainer)

override fun onVisibleAreaChanged(visibleArea: Rect) =
carMapSurfaceOwner.onVisibleAreaChanged(visibleArea)

override fun onStableAreaChanged(stableArea: Rect) =
carMapSurfaceOwner.onStableAreaChanged(stableArea)

override fun onScale(focusX: Float, focusY: Float, scaleFactor: Float) =
carMapSurfaceOwner.onScale(focusX, focusY, scaleFactor)

override fun onScroll(distanceX: Float, distanceY: Float) =
carMapSurfaceOwner.onScroll(distanceX, distanceY)

override fun onFling(velocityX: Float, velocityY: Float) =
carMapSurfaceOwner.onFling(velocityX, velocityY)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.car.app.CarAppService
import androidx.car.app.Session
import androidx.car.app.validation.HostValidator
import com.mapbox.maps.testapp.auto.car.MapSession
import com.mapbox.maps.testapp.auto.custom.CustomMapSession

/**
* Entry point for the templated app.
Expand All @@ -18,6 +19,17 @@ class MapboxCarAppService : CarAppService() {
}

override fun onCreateSession(): Session {
return MapSession()
return if (enableCustomCallback) {
CustomMapSession()
} else {
MapSession()
}
}

companion object {
/**
* This can be toggled by the mobile app.
*/
var enableCustomCallback = false
}
}
14 changes: 13 additions & 1 deletion android-auto-app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,25 @@
tools:context=".app.MainActivity">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Android Auto testing activity"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="Android Auto testing activity"
tools:ignore="HardcodedText" />

<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enable onClick"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:ignore="HardcodedText"/>

</androidx.constraintlayout.widget.ConstraintLayout>
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Project.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ object AndroidVersions {
object AndroidAuto {
const val minSdkVersion = 23
const val targetSdkVersion = 30
const val compileSdkVersion = 31
const val compileSdkVersion = 33
}
object Compose {
const val minSdkVersion = 23
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import java.util.concurrent.CopyOnWriteArraySet
* Maintains the surface state for [MapboxCarMap].
*/
@MapboxExperimental
internal class CarMapSurfaceOwner(
class CarMapSurfaceOwner(
var gestureHandler: MapboxCarMapGestureHandler? = DefaultMapboxCarMapGestureHandler()
) : SurfaceCallback {

Expand All @@ -35,14 +35,14 @@ internal class CarMapSurfaceOwner(

private val carMapObservers = CopyOnWriteArraySet<MapboxCarMapObserver>()

fun setup(carContext: CarContext, mapInitOptions: MapInitOptions) = apply {
internal fun setup(carContext: CarContext, mapInitOptions: MapInitOptions) = apply {
this.carContext = carContext
this.mapInitOptions = mapInitOptions
}

fun isSetup(): Boolean = this::carContext.isInitialized && this::mapInitOptions.isInitialized
internal fun isSetup(): Boolean = this::carContext.isInitialized && this::mapInitOptions.isInitialized

fun registerObserver(mapboxCarMapObserver: MapboxCarMapObserver) {
internal fun registerObserver(mapboxCarMapObserver: MapboxCarMapObserver) {
carMapObservers.add(mapboxCarMapObserver)
logI(TAG, "registerObserver + 1 = ${carMapObservers.size}")

Expand All @@ -55,13 +55,13 @@ internal class CarMapSurfaceOwner(
}
}

fun unregisterObserver(mapboxCarMapObserver: MapboxCarMapObserver) {
internal fun unregisterObserver(mapboxCarMapObserver: MapboxCarMapObserver) {
carMapObservers.remove(mapboxCarMapObserver)
mapboxCarMapSurface?.let { mapboxCarMapObserver.onDetached(it) }
logI(TAG, "unregisterObserver - 1 = ${carMapObservers.size}")
}

fun clearObservers() {
internal fun clearObservers() {
this.mapboxCarMapSurface?.let { surface -> carMapObservers.forEach { it.onDetached(surface) } }
carMapObservers.clear()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.graphics.Rect
import androidx.car.app.AppManager
import androidx.car.app.CarContext
import androidx.car.app.Session
import androidx.car.app.SurfaceCallback
import androidx.lifecycle.Lifecycle
import com.mapbox.maps.EdgeInsets
import com.mapbox.maps.MapInitOptions
Expand Down Expand Up @@ -78,6 +79,27 @@ class MapboxCarMap {
carContext.getCarService(AppManager::class.java).setSurfaceCallback(carMapSurfaceOwner)
}

/**
* Instead of using [setup], this function allows you to create your own [SurfaceCallback] and
* forward the calls to the [CarMapSurfaceOwner]. This makes it possible for you to adopt new
* api versions and continue to use the [MapboxCarMap] as designed.
*
* This is a temporary solution, while androidx.car.app:app:1.3.0 is rolling out
* [SurfaceCallback.onClick]. If there is no longer a use for this function in the future, it
* will be removed.
*/
@MapboxExperimental
fun setupWithCustomCallback(
carContext: CarContext,
mapInitOptions: MapInitOptions
): CarMapSurfaceOwner {
check(mapInitOptions.context is CarContext) {
"You must setup the MapboxCarMap MapInitOptions with a CarContext"
}
carMapSurfaceOwner.setup(carContext, mapInitOptions)
return carMapSurfaceOwner
}

/**
* Returns the current [MapboxCarMapSurface]. It is recommended to use [registerObserver] and
* [MapboxCarMapObserver] to attach and detach your customizations.
Expand Down

0 comments on commit 955f14c

Please sign in to comment.