Skip to content

Repository files navigation

CafariCarCanvas

A small Android library for putting your app's video on a car screen — Android Auto and cars with Google built-in — through the official Android for Cars App Library.

You implement one interface (CarCanvasSink) and get a Surface, its size, and the area you may draw in. The library owns the car-side plumbing: service, session, screen, surface lifecycle, visible/stable areas, drive-state handoff.

public class MyCarService extends CarCanvasService {
    @NonNull @Override
    protected CarCanvasSink createSink(@NonNull CarContext ctx) {
        return new ExoPlayerSink(ctx, "https://example.com/stream.m3u8");
    }
}

Plus a manifest entry (see sample/src/main/AndroidManifest.xml). That is the whole integration.

Read this before you start

An app installed any way other than from Google Play will not appear on the car screen. Android Auto checks the installing package, and apps built with the car app library are exempted from the "unknown sources" developer toggle. A debug build over adb, an APK from a release page, an F-Droid install — the host ignores all of them. So:

  • Developing: use the Desktop Head Unit, which works with a local debug build.
  • Shipping: publish through your own Play listing. Production, closed or internal testing tracks all give the package com.android.vending provenance. Check with adb shell pm get-install-source <your.package>.

This is a property of the platform, not of this library, and nothing in this repo can work around it. It also means each integrator publishes under their own developer account and is responsible for what their app does on the car screen.

Choosing a category

The <category> in your service's intent filter decides both where the host lists the app and whether it may draw at all.

Category Draws a surface Notes
androidx.car.app.category.NAVIGATION yes What the sample uses. Widest availability today.
androidx.car.app.category.POI yes Same surface access, different placement.
Media template category no Templates only — no surface.

As of September 2026 a dedicated video category exists on cars with Google built-in (declare android:appCategory="video"), and Google has announced the same for Android Auto "later in 2026", needing Android 17+ on the phone and a compatible car. When that lands, prefer it: it is the supported route for video and carries none of the ambiguity of drawing video on a navigation surface. Until then, and for older phones and cars afterwards, navigation or POI is the only way.

Whichever you pick, your app must still satisfy Google's car app quality guidelines for that category, and playing video while the car moves is what gets apps and accounts removed. Source a drive state and pass it to CarCanvasScreen.setDriveState(parked); the library forwards it to your sink and the sample stops playback. The library deliberately does not read car hardware itself — that needs a permission you must declare and justify, and "may play" is a policy decision that belongs to whoever ships the app.

Feeding it your own frames

A sink is not tied to ExoPlayer. If your app already encodes or decodes video — a browser casting a tab, a mirroring app — take the Surface from onSurfaceAvailable and render into it directly (MediaCodec.configure(..., surface, ...), an ImageReader, GL, whatever you have). Media3 is a dependency of :sample only; :carcanvas depends on nothing but androidx.car.app.

For fitting content of a different aspect into the head unit's usable area, and for mapping car touches back to content coordinates, see CarCanvasGeometry.

Layout

carcanvas/   the library — CarCanvasService, CarCanvasScreen, CarCanvasSink, CarCanvasGeometry
aidl/        the IPC contract, for clients that talk to the bridge (no other dependencies)
bridge/      the bridge app: owns the car display, serves a client app over AIDL
sample/      a minimal app that plays one stream on the car display

The bridge, and why it exists

The host ignores any car app not installed from Play (see above). That is fatal for an app you distribute yourself — a browser, a media app with its own store, anything sideloaded.

bridge/ solves it by splitting the problem: the bridge is a tiny app you publish on Play, and it is the only thing the car ever talks to. Your app binds it over AIDL and supplies the content, and can be distributed any way you like.

Two modes, because neither covers everything:

URL mode (loadMedia) Surface mode (requestSurface)
Your app supplies a stream URL + headers frames
Who renders the bridge's ExoPlayer your app, into the car Surface
Cost on the phone none a scale + colour convert per frame (no encode — the car host encodes)
Works when you can resolve a real URL always: MSE/blob players, canvas, a whole page

A client picks per cast: URL mode when it extracted one, surface mode otherwise. Surface mode passes the car's Surface across the process boundary, which works because Surface is Parcelable — your app draws into it exactly as if it owned it.

Access is a signature-level permission, so only an app signed with the bridge's own key may bind it. An open bridge would let any app on the phone draw on a driver's display; if you need a differently-signed client, add an explicit package + certificate allowlist rather than removing the check.

DRM content is out of scope: a licence cannot be delegated to another app's player, and protected frames cannot be drawn into a capture surface.

Build: ./gradlew :sample:assembleDebug (JDK 17, Android SDK 34).

Maven coordinates once published: ai.rplay.cafari.carcanvas:carcanvas.

Prior art

Apps doing this exist — ihueDashPlayer draws a hidden WebView onto the car screen, Android-auto-media-player registers as NAVIGATION rather than MEDIA for the same SurfaceContainer access. What is missing is the reusable piece, which is what this is.

Status

Early. The API compiles and the shape is settled, but it has not been run against a real head unit yet — next step is a Desktop Head Unit pass, then a car.

License

Apache-2.0. Copyright 2026 rPlay AI.

Contributions welcome — see CONTRIBUTING.md.

About

Put your app's video on the car screen (Android Auto and cars with Google built-in) — a thin library over androidx.car.app, plus a bridge app for self-distributed clients. Extracted from Cafari.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages