Kiến Thức Chung

Using the Android for Cars App Library

Version 1.1.0 of the Android for Cars App Library is in alpha. Features introduced in this version that require Car App API level 2 and higher can only be used in the Android Auto Desktop Head Unit. We will make announcements in the future when these features are available in actual cars.

The Android for Cars App Library
allows you to bring your navigation, parking, and charging apps to the car.
It does so by providing a set of templates designed to meet driver distraction
standards and taking care of details such as the variety of car screen factors
and input modalities.

This guide provides an overview of the library’s key features and concepts, and
walks you through the process of setting up a simple app.

Important:

Google takes driver distraction very seriously. Your app must belong to one of the supported categories and meet specific design requirements, before it can be listed on Google Play for Android Auto. By adhering to these requirements, you can make it easier to build and test your app. For more information, see Android app quality for cars

Important:

Features that require Car App API level 2 and higher are only supported by Android Auto version 6.6. Join the Android Auto open beta track to receive the latest updates to Android Auto. Note that the Android Auto open beta track has fewer stability guarantees than the Android Auto production track.

Important:

There is currently no way to run an Android Automotive OS Car App Library sample app . We will make announcements in the future when the Car App Library is available for Android Automotive OS.

Note:

As mentioned in our Jetpack release announcement , the closed source library will no longer be available and the Google Play Store will not accept submissions that depend on that library starting September 1, 2021. It is currently still available for internal, closed, and open testing. Refer to the Migration Guide for instructions on how to migrate your app written with the closed source library to the Jetpack library.

Before you begin

Key terms and concepts

Models and Templates
The user interface is represented by a graph of model objects that can be
arranged together in different ways as allowed by the template they belong to.
Templates are a subset of the models that can act as a root in those graphs.
Models include the information to be displayed to the user, in the form of text
and images, as well as attributes to configure aspects of the visual appearance
of such information (for example, text colors or image sizes). The host
converts the models to views that are designed to meet driver distraction
standards and takes care of details such as the variety of car screen factors
and input modalities.
Host
The host is the back end component that implements the functionality offered
by the library’s APIs in order for your app to run in the car. The
responsibilities of the host range from discovering your app and managing its
lifecycle, to converting your models into views and notifying your app of user
interactions. On mobile devices, this host is implemented by Android Auto.
Template restrictions
Different templates enforce restrictions in the content of their models. For
example, list templates have limits on the number of items that can be presented
to the user. Templates also have restrictions in the way they can be connected
to form the flow of a task. For example, the app can only push up to 5 templates
to the screen stack. See Template restrictions for
more details.
Screen
A Screen is a class provided by the
library that apps implement to manage the user interface presented to the user.
A Screen has a lifecycle
and provides the mechanism for the app to send the template to display when the
screen is visible. Screen instances can
also be pushed and popped to and from a Screen stack,
which ensures they adhere to the template flow restrictions.
CarAppService
A CarAppService is an abstract
Service class that your app must implement
and export in order to be discovered and managed by the host. Your app’s
CarAppService is responsible for
validating that a host connection can be trusted using
CarAppService.createHostValidator,
and subsequently providing Session
instances for each connection using CarAppService.onCreateSession.
Session

A Session is an abstract class that
your app must implement and return using CarAppService.onCreateSession.
It serves as the entry point to display information on the car screen, and has a
lifecycle that informs the current state of your app on the
car screen, such as when your app is visible or hidden.

When a Session is started (such as
when the app is first launched), the host requests for the initial Screen
to display using the Session.onCreateScreen
method.

Install the library

Please follow the Jetpack library release page
for instructions on how to add the library to your app.

Important:

When depending on alpha and beta releases of the library, take extra
caution when using newly introduced or experimental APIs. Specifically, new APIs
in alpha releases or APIs that are annotated as experimental may change and
potentially break your app when the host(s) are updated. We strongly recommend
against referencing these categories of APIs in your production APKs
.

Configure your app’s manifest files

Before you can create your car app, you need to configure your app’s
manifest files.

Declare your CarAppService

The host connects to your app through your CarAppService
implementation. You declare this service in your manifest to allow the host to
discover and connect to your app.

You also need to declare your app’s category in the
category element of your app’s
intent filter. See the list of supported app categories
for the values allowed for this element.

The following code snippet shows how to declare a car app service for a parking
app in your manifest:

<application>
    ...
   <service
       ...
        android:name=".MyCarAppService"
        android:exported="true">
      <intent-filter>
        <action android:name="androidx.car.app.CarAppService"/>
        <category android:name="androidx.car.app.category.PARKING"/>
      </intent-filter>
    </service>

    ...
<application>

Supported App Categories

In order to be listed in the Play Store for Android Auto, the app needs to
belong to one of the supported car app categories. You declare your app’s
category by adding one or more of the following supported category values in
the intent filter when you declare your car app service:

  • androidx.car.app.category.NAVIGATION: An app that provides
    turn-by-turn navigation directions.
  • androidx.car.app.category.PARKING: An app that provides functionality
    relevant to finding parking spots.
  • androidx.car.app.category.CHARGING: An app that provides functionality
    relevant to finding electric vehicle charging stations.

Xem thêm:   Build PC chơi GÊM 19 củ khoai

Xem thêm :  Cách chơi trò chơi nhảy cóc dân gian vô cùng đơn giản

See Android app quality for cars for
the detailed description and criteria for apps to belong to each category.

Note:

The car app category is unrelated to the category you choose for listing
your app in Google Play, which is used for helping users discover the most
relevant apps in the Play Store.

Specify the app name and icon

You need to specify an app name and icon that the host can use to represent your
app in the system UI.

You can specify the app name and icon that is used to represent your app using
the label and
icon elements of your
CarAppService:

...
<service
   android:name=".MyCarAppService"
   android:exported="true"
   android:label="@string/my_app_name"
   android:icon="@drawable/my_app_icon">
   ...
</service>
...

If the label or icon are not declared in the
service element, the host will fall
back to the values specified for the application.

Car App API level

Note:

Version 1.1.0 of the Android for Cars App Library is in alpha. Features introduced in this version that require Car App API level 2 and higher can only be used in the Android Auto Desktop Head Unit.

The Car App Library defines its own API levels so that you can know which
features of the library are supported by the template host on a given vehicle.
To retrieve the highest Car App API Level supported by a host, use the
getCarAppApiLevel() method.

You must declare the minimum Car App API Level supported by your app in your
AndroidManifest.xml file:

<manifest ...>
    <application ...>
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"/>
    </application>
</manifest>

See the documentation for the
RequiresCarApi
annotation for details on how to maintain backwards compatibility and declare
the minimum API level required to use a feature. For a
definition of which API Level is required to use a certain feature of the Car
App Library, check the reference documentation for
CarAppApiLevels.

Create your CarAppService and Session

Your app needs to extend the CarAppService
class and implement the CarAppService.onCreateSession
method, which returns a Session
instance corresponding to the current connection to the host:

Kotlin

class HelloWorldService : CarAppService() {
    ...
    override fun onCreateSession(): Session {
        return HelloWorldSession()
    }
    ...
}

Java

public final class HelloWorldService extends CarAppService {
    ...
    @Override
    @NonNull
    public Session onCreateSession() {
        return new HelloWorldSession();
    }
    ...
}

The Session instance is responsible for
returning the Screen instance to use the
first time the app is started:

Kotlin

class HelloWorldSession : Session() {
    ...
    override fun onCreateScreen(intent: Intent): Screen {
        return HelloWorldScreen()
    }
    ...
}

Java

public final class HelloWorldSession extends Session {
    ...
    @Override
    @NonNull
    public Screen onCreateScreen(@NonNull Intent intent) {
        return new HelloWorldScreen();
    }
    ...
}

To handle scenarios where your car app needs to start from a screen that is not
the home or landing screen of your app (such as handling deep links), you can
pre-seed a back stack of screens using ScreenManager.push.
before returning from onCreateScreen.
Pre-seeding allows users to navigate back to previous screens from the first
screen that your app is showing.

Create your start screen

You create the screens displayed by your app by defining classes that extend the
Screen class and implementing the
Screen.onGetTemplate
method, which returns the Template
instance representing the state of the UI to display in the car screen.

The following snippet shows how to declare a Screen
that uses a PaneTemplate
template to display a simple “Hello world!” string:

Kotlin

class HelloWorldScreen(carContext: CarContext) : Screen(carContext) {
    override fun onGetTemplate(): Template {
        val row = Row.Builder().setTitle("Hello world!").build()
        val pane = Pane.Builder().addRow(row).build()
        return PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build()
    }
}

Java

public class HelloWorldScreen extends Screen {
    @NonNull
    @Override
    public Template onGetTemplate() {
        Row row = new Row.Builder().setTitle("Hello world!").build();
        Pane pane = new Pane.Builder().addRow(row).build();
        return new PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build();
    }
}

The CarContext class

The CarContext class is a
ContextWrapper subclass
accessible to your Session and
Screen instances, which provides access
to car services such as the ScreenManager
for managing the screen stack, the AppManager
for general app-related functionality such as accessing the Surface object for
drawing your navigation app’s map, and the
NavigationManager
used by turn-by-turn navigation apps to communicate navigation metadata
and other navigation-related events with
the host. See Access the navigation templates
for a comprehensive list of library functionality available to navigation apps.

The CarContext also offers other
functionality such as allowing loading drawableresources using the configuration
from the car screen, starting an app in the car using intents,
and signaling whether your navigation app should display its map
in dark mode.

Implement screen navigation

Apps often present a number of different screens, each possibly utilizing
different templates, that the user can navigate through as they interact with
the interface displayed in the screen.

The ScreenManager class provides
a screen stack that you can use to push screens that can be popped automatically
when the user selects a back button in the car screen, or uses the hardware back
button available in some cars.

The following snippet shows how to add a back action to message template, as
well as an action that pushes a new screen when selected by the user:

Kotlin

val template = MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener { screenManager.push(NextScreen(carContext)) }
            .build())
    .build()

Java

MessageTemplate template = new MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        new Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener(
                () -> getScreenManager().push(new NextScreen(getCarContext())))
            .build())
    .build();

The Action.BACK object is a
standard Action that automatically
invokes ScreenManager.pop.
This behavior can be overridden by using the OnBackPressedDispatcher
instance available from the CarContext.

To ensure the app is safe while driving, the screen stack can have a maximum
depth of 5 screens. See Template restrictions for more
details.

Refresh the contents of a template

Your app can request the content of a Screen
to be invalidated by calling the Screen.invalidate
method. The host subsequently calls back into your app’s
Screen.onGetTemplate
method to retrieve the template with the new contents.

When refreshing a Screen, it is
important to understand the specific content in the template that can be updated
so that the host will not count the new template against the template quota.
See Template restrictions for more details.

It is recommended that you structure your screens so that there is a
one-to-one mapping between a Screen and
the type of template it returns through its Screen.onGetTemplate
implementation.

Interact with the user

Your app can interact with the user using patterns similar to your mobile app.

Handle user input

Your app can respond to user input by passing the appropriate listeners to the
models that support them. The following snippet shows how to create an
Action model that sets an
OnClickListener that
calls back to a method defined by your app’s code:

Kotlin

val action = Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(::onClickNavigate)
    .build()

Java

Action action = new Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(this::onClickNavigate)
    .build();

The onClickNavigate method can then start the default navigation car app by
using the CarContext.startCarApp
method:

Kotlin

private fun onClickNavigate() {
    val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address))
    carContext.startCarApp(intent)
}

Java

private void onClickNavigate() {
    Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
    getCarContext().startCarApp(intent);
}

For more details on how to start apps, including the format of the
ACTION_NAVIGATE intent, see Start a car app with an intent.

Some actions, such as those that require directing the user to continue the
interaction on their mobile devices, are only allowed when the car is parked.
You can use the ParkedOnlyOnClickListener
to implement those actions. If the car is not parked, the host will display an
indication to the user that the action is not allowed in this case. If the car
is parked, the code will execute normally. The following snippet shows how to
use the ParkedOnlyOnClickListener
to open a settings screen on the mobile device:

Xem thêm:   BÀI 7: HƯỚNG DẪN VẼ TƯỜNG, HATCH TƯỜNG, XỬ LÝ TƯỜNG (tiếp theo)

Xem thêm :  Học cách buôn bán nhỏ lẻ tại nhà hiệu quả!

Kotlin

val row = Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone))
    .build()

Java

Row row = new Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone))
    .build();

Display notifications

Notifications sent to the mobile device will only show up in the car screen if
they are extended with a CarAppExtender.
Some notification attributes, such as content title, text, icon, and actions,
can be set in the CarAppExtender, overriding the notification’s attributes
when appearing in the car screen.

The following snippet shows how to send a notification to the car screen that
displays a different title than the one shown on the mobile device:

Kotlin

val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build()

Java

Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        new CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build();

Notifications can affect the following parts of the user interface:

  • A heads-up notification (HUN) may be displayed to the user.
  • An entry in the notification center may be added, optionally with a badge
    visible in the rail.
  • For navigation apps, the notification may be displayed in the rail widget as
    described in Turn-by-turn notifications.

Applications can choose how to configure their notifications to affect each of
those user interface elements by using the notification’s priority, as described
in the CarAppExtender
documentation.

If NotificationCompat.Builder.setOnlyAlertOnce
is called with a value of true, a high-priority notification will display as
a HUN only once.

For more information on how to design your car app’s notifications, see
Notifications.

Note:

The library does not provide the ability to send a notification only to
the car screen and not to the mobile device.

Show toasts

Your app can display a toast using CarToast
as shown in this snippet:

Kotlin

CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()

Java

CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();

Request permissions

If your app needs access to restricted data or actions (for example, getting
location access),
standard rules of Android permissions
apply to your app as well. To request a permission, you can use the
CarContext.requestPermissions()
method. On Android Auto, the permissions dialog for the user will appear on the
phone.

The benefit of using
CarContext.requestPermissions()
as opposed to using
standard Android APIs
is that you don’t need to launch your own Activity for the sole purpose of
creating the permissions dialog. When Android Automotive OS support is available
later in the year, you’ll also be able to use the same code on both Android Auto
and Android Automotive OS rather than having to create platform-dependent flows.

Start a car app with an intent

You can call the CarContext.startCarApp
method to perform one of the following actions:

  • Open the dialer to make a phone call.
  • Start turn-by-turn navigation to a location with the default navigation car app.
  • Start your own app with an intent.

The following example shows how to create a notification with an action that
opens your app with a screen that shows the details of a parking reservation.
You extend the notification instance with a content intent that contains a
PendingIntent wrapping an explicit
intent to your app’s action:

Kotlin

val notification = notificationBuilder
    ...
    .extend(
        CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(ComponentName(context, MyNotificationReceiver::class.java)),
                    0))
            .build())

Java

Notification notification = notificationBuilder
    ...
    .extend(
        new CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    new Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(new ComponentName(context, MyNotificationReceiver.class)),
                    0))
            .build());

Your app must also declare a BroadcastReceiver
that is invoked to process the intent when the user selects the action in the
notification interface and invokes CarContext.startCarApp
with an intent including the data URI:

Kotlin

class MyNotificationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val intentAction = intent.action
        if (ACTION_VIEW_PARKING_RESERVATION == intentAction) {
            CarContext.startCarApp(
                intent,
                Intent(Intent.ACTION_VIEW)
                    .setComponent(ComponentName(context, MyCarAppService::class.java))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)))
        }
    }
}

Java

public class MyNotificationReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) {
            CarContext.startCarApp(
                intent,
                new Intent(Intent.ACTION_VIEW)
                    .setComponent(new ComponentName(context, MyCarAppService.class))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)));
        }
    }
}

Finally, the Session.onNewIntent
method in your app handles this intent by pushing the parking reservation screen
on the stack if not already on top:

Kotlin

override fun onNewIntent(intent: Intent) {
    val screenManager = carContext.getCarService(ScreenManager::class.java)
    val uri = intent.data
    if (uri != null
        && MY_URI_SCHEME == uri.scheme
        && MY_URI_HOST == uri.schemeSpecificPart
        && ACTION_VIEW_PARKING_RESERVATION == uri.fragment
    ) {
        val top = screenManager.top
        if (top !is ParkingReservationScreen) {
            screenManager.push(ParkingReservationScreen(carContext))
        }
    }
}

Java

@Override
public void onNewIntent(@NonNull Intent intent) {
    ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
    Uri uri = intent.getData();
    if (uri != null
        && MY_URI_SCHEME.equals(uri.getScheme())
        && MY_URI_HOST.equals(uri.getSchemeSpecificPart())
        && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment())
    ) {
        Screen top = screenManager.getTop();
        if (!(top instanceof ParkingReservationScreen)) {
            screenManager.push(new ParkingReservationScreen(getCarContext()));
        }
    }
}

See Display notifications for more information on how
to handle notifications for the car app.

Template restrictions

The host limits the number of templates to display for a given task to a maximum
of 5, of which the last template of the 5 must be one of the following types:

Note that this limit applies to the number of templates, and not the
number of Screen instances in the stack.
For example, if while in screen A an app sends 2 templates, and then pushes
screen B, it can now send 3 more templates. Alternatively, if each screen is
structured to send a single template, then the app can push 5 screen instances
onto the ScreenManager stack.

Caution:

If the template quota is exhausted and the app attempts to send a new
template, the host will display an error message to the user before closing the
app.

Note:Enable debug overlay in the Developer Settings screen.

During development with Android Auto, you can see the current number of steps overlaid on the screen by first enabling Developer Mode , and then checkingin thescreen.

There are special cases to these restrictions: template refreshes, back and
reset operations.

Template refreshes

Certain content updates are not counted towards the template limit. In general,
as long as an app pushes a new template that is of the same type and contains
the same main content as the previous template, the new template will not be
counted against the quota. For example, updating the toggle state of a row in a
ListTemplate does not count
against the quota. See the documentation of individual templates to learn more
about what types of content updates can be considered a refresh.

Back operations

To enable sub-flows within a task, the host detects when an app is popping a
Screen from the ScreenManager
stack, and updates the remaining quota based on the number of templates that the
app is going backwards by.

For example, if while in screen A, the app sends 2 templates and then pushes
screen B and sends 2 more templates, then the app has 1 quota remaining. If
the app now pops back to screen A, the host will reset the quota to 3, because
the app has gone backwards by 2 templates.

Note that when popping back to a screen, an app must send a template that is
of the same type as the one last sent by that screen. Sending any other
template types would cause an error. However, as long as the type remains the
same during a back operation, an app can freely modify the contents of the
template without affecting the quota.

Reset operations

Certain templates have special semantics that signify the end of a task. For
example, the NavigationTemplate
is a view that is expected to stay on the screen and be refreshed with new
turn-by-turn instructions for the user’s consumption. Upon reaching one of these
templates, the host will reset the template quota, treating that template as if
it is the first step of a new task, thus allowing the app to begin a new task.
See the documentation of individual templates to see which ones trigger a reset
on the host.

Xem thêm:   Cách làm cho ổ cứng chạy mượt như lúc mới mua

Xem thêm :  Tháng 9/2021 lãi suất gửi tiết kiệm ngân hàng nào cao nhất?

If the host receives an intent to start the app from a notification action or
from the launcher, the quota will also be reset. This mechanism allows an app to
begin a new task flow from notifications, and it holds true even if an app is
already bound and in the foreground.

See Display notifications for more details on how to
display your app’s notifications in the car screen, and
Start a car app with an intent for how to
start your app from a notification action.

Add a sign-in flow

If your app offers a signed-in experience for users, you can use templates such
as the SignInTemplate
and LongMessageTemplate
with Car App API level 2 and above to handle signing in to your app on the
car’s head unit.

To create a SignInTemplate, you will need to define a SignInMethod. The Car
App Library currently supports three sign-in methods:

  • InputSignInMethod
    for Username/Password sign-in
  • PinSignInMethod
    for Pin code sign-in, where the user links their account from their phone using
    a pin displayed on the head unit
  • ProviderSignInMethod
    for Provider sign-in, such as Google Sign-In

For example, to implement a template that collects the user’s password, start by
creating an InputCallback
to process and validate user input:

Kotlin

val callback = object : InputCallback {
    override fun onInputSubmitted(text: String) {
        // You will receive this callback when the user presses enter on the keyboard.
    }

    override fun onInputTextChanged(text: String) {
        // You will receive this callback as the user is typing. The update frequency is determined by the host.
    }
}

Java

InputCallback callback = new InputCallback() {
    @Override
    public void onInputSubmitted(@NonNull String text) {
        // You will receive this callback when the user presses enter on the keyboard.
    }

    @Override
    public void onInputTextChanged(@NonNull String text) {
        // You will receive this callback as the user is typing. The update frequency is determined by the host.
    }
};

An InputCallback is required for the InputSignInMethod Builder.

Kotlin

val passwordInput = InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build()

Java

InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build();

Finally, use your new InputSignInMethod to create a SignInTemplate.

Kotlin

SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build()

Java

new SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build();

Add text string variants

Different car screen sizes may show different amounts of text. With Car App API
level 2 and above, you can specify multiple variants of a text string to best
fit the screen. To see where text variants are accepted, look for templates and
components that take a CarText.

You can add text string variants to a
CarText with the
CarText.Builder.addVariant() method:

Kotlin

val itemTitle = CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build()

Java

CarText itemTitle = new CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build();

You can then use this CarText,
for example, as the primary text of a
GridItem.

Kotlin

GridItem.Builder()
    .addTitle(itemTitle)
    ...
    .build()

Java

new GridItem.Builder()
    .addTitle(itemTitle)
    ...
    build();

Add strings in order from most to least preferred, for example, from longest to
shortest. The host will pick the appropriate length string depending on the
amount of space available on the car screen.

Car Hardware APIs

Starting with Car App API level 3, the Car App Library introduces APIs that you
can use to access vehicle properties and sensors.

Requirements

To use the APIs with Android Auto, start by adding a dependency on
androidx.car.app:app-projected to the build.gradle file for your Android
Auto module.

Additionally, in your AndroidManifest.xml file, you will need to
declare the relevant permissions needed to
request the car data you’d like to use. Note that these permissions must also be
granted to you by the user.

CarInfo

This table describes the properties surfaced by the
CarInfo APIs and the
permissions you’ll need to request to use them:

Methods
Properties
Permissions

fetchModel
Make, Model, Year

fetchEnergyProfile
EV connector types, Fuel types
com.google.android.gms.permission.CAR_FUEL
addTollListener

removeTollListener
Toll card state, Toll card type

addEnergyLevelListener

removeEnergyLevelListener
Battery level, Fuel level, Fuel level low, Range remaining
com.google.android.gms.permission.CAR_FUEL
addSpeedListener

removeSpeedListener
Raw speed, Display speed (shown on car’s cluster display)
com.google.android.gms.permission.CAR_SPEED
addMileageListener

removeMileageListener
Odometer distance
com.google.android.gms.permission.CAR_MILEAGE

For example, to get the remaining range, instantiate a
CarInfo object, then
create and register an OnCarDataAvailableListener:

Kotlin

val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo

val listener = OnCarDataAvailableListener<EnergyLevel> { data ->
    if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) {
      val rangeRemaining = data.rangeRemainingMeters.value
    } else {
      // Handle error
    }
  }

carInfo.addEnergyLevelListener(carContext.mainExecutor, listener)
…
// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener)

Java

CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo();

OnCarDataAvailableListener<EnergyLevel> listener = (data) -> {
  if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) {
    float rangeRemaining = data.getRangeRemainingMeters().getValue();
  } else {
    // Handle error
  }
};

carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener);
…
// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener);

You should not assume that the data from the car will be available at all times.
If you get an error, check the
status of
the value you requested to better understand why the data you requested could
not be retrieved. Refer to the
reference documentation
for the full CarInfo class definition.

When Android Automotive OS support is available later in the year, you’ll also
be able to use the same code on both Android Auto and Android Automotive OS
rather than having to create platform-dependent flows. However, the permissions
needed on Android Automotive OS will be different.

CarSensors

The CarSensors class
gives you access to the vehicle’s accelerometer, gyroscope, compass, and
location data, but note that the availability of these values may depend on the
OEM. The format for the data from the accelerometer, gyroscope, and compass is
the same as you would get from the
SensorManager API. For example,
to check the vehicle’s heading:

Kotlin

val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors

val listener = OnCarDataAvailableListener<Compass> { data ->
    if (data.orientations.status == CarValue.STATUS_SUCCESS) {
      val orientation = data.orientations.value
    } else {
      // Data not available, handle error
    }
  }

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener)
…
// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener)

Java

CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors();

OnCarDataAvailableListener<Compass> listener = (data) -> {
  if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) {
    List<Float> orientations = data.getOrientations().getValue();
  } else {
    // Data not available, handle error
  }
};

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(),
    listener);
…
// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener);

To access location data from the car, you also need to declare and
request the android.permission.ACCESS_FINE_LOCATION permission.

The CarAppService, Session and Screen Lifecycles

The Session and Screen
classes implement the LifecycleOwner
interface. As the user interacts with the app, your Session and Screen
objects’ lifecycle callbacks will be invoked, as described in the following
diagrams.

The lifecycles of a CarAppService and a Session


Figure 1. The Session lifecycle.

For full details see the documentation of Session.getLifecycle
method.

The lifecycle of a Screen


Figure 2. The Screen lifecycle.

For full details see the documentation of
Screen.getLifecycle.

Testing Library

The Android for Cars Testing Library
provides auxiliary classes that you can use to validate your apps’ behavior in
a test environment. For example, the SessionController
allows you to simulate a connection to the host and verify that the correct
Screen and Template
are created and returned.

Refer to the Samples
for usage examples.

Report an Android for Cars App Library issue

If you find an issue with the library, report it using the
Google Issue Tracker. Be
sure to fill out all the requested information in the issue template.

Create a new issue

Before filing a new issue, please check if it is listed in the library’s release
notes or reported in the issues list. You can subscribe and vote for issues by
clicking the star for an issue in the tracker. For more information, see
Subscribing to an Issue.

Xem thêm bài viết thuộc chuyên mục: Tips – IT and Computing

Related Articles

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Back to top button