Google is committed to advancing racial equity for Black communities. See how.

Consuming Car Driving State and UX Restrictions

This article explains how applications can transition gracefully to Distraction Optimized (DO) user interfaces. It describes how to consume a car's driving state as well as the corresponding user experience restrictions. For more information about Car User Experience (UX) Restrictions rules, see Car User Experience Restrictions, which details the three driving states of Parked, Idling, and Moving.

Audience

This content is provided for those who want to design applications that adapt to changes in a car's driving state and the correspondingly imposed UX restrictions.

Technical Details

CarDrivingStateManager

A car's driving state (Parked, Idling, or Moving) is derived from the sensor values provided by the Vehicle Hardware Abstraction Layer (VHAL). Basic sensor information, such as vehicle speed and current gear selection, is used to derive the vehicle's current driving state.

This information is exposed to privileged clients by means of CarDrivingStateManager, which provides @SystemApis, meaning that only Platform Internals, Bundled APKs (such as SysUI or Settings), and Privileged APKs (such as) GMSCore can access the APIs. The APIs are protected by permissions specific to driving state android.car.permission.CAR_DRIVING_STATE. Clients that require access to driving state information must request this permission.

CarUxRestrictionsManager

Those applications that display a user interface dependent upon driving state must listen to CarUxRestrictionsManager, which abstracts the mapping from driving state to UX restrictions so that applications need not adjust for different market safety requirements.

Note: These activities must be marked as DistractionOptimized, as described in Driver Distraction Guidelines. If the activities are not marked accordingly, they will be blocked.

Instead, applications monitor restrictions exposed by the CarUxRestrictionsManager and not an absolute driving state exposed by the CarDrivingStateManager for anything related to the user interface or the user experience.

Code Sample

The following sample code illustrates how an application monitors UX restrictions:

  1. Import the car library packages:
    import android.car.Car;
    /* For CarUxRestrictions */
    import android.car.drivingstate.CarUxRestrictions;
    import android.car.drivingstate.CarUxRestrictionsManager;
    
  2. Implement the CarUxRestrictionManager.OnUxRestrictionsChangedListener (mUxRChangeListener). This listener, once registered with the CarUxRestrictionsManager, will be called when a change in the UX restrictions occurs. Handle the restriction changes to be Distraction Optimized, as needed:
    @Nullable private CarUxRestrictionsManager mCarUxRestrictionsManager;
    private CarUxRestrictions mCurrentUxRestrictions;
    
    /* Implement the onUxRestrictionsChangedListener interface */
    private CarUxRestrictionsManager.OnUxRestrictionsChangedListener mUxrChangeListener =
                new CarUxRestrictionsManager.onUxRestrictionsChangedListener()
        {
            @Override
            public void onUxRestrictionsChanged(CarUxRestrictions carUxRestrictions) {
            mCurrentUxRestrictions = carUxRestrictions;
            /* Handle the new restrictions */
            handleUxRestrictionsChanged(carUxrestrictions);
            }
        };
      
  3. Call the car APIs to create a car instance named mCar and connect to the car service:
    mCar = Car.createCar(context);
    if (mCar == null) {
    // handle car connection error
    }
    
  4. Call mCar.getCarManager() - mCarUxRestrictionsManager to get the CarUxRestrictionsManager:
    CarUxRestrictionsManager carUxRestrictionsManager = (CarUxRestrictionsManager)
    mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
    
  5. To register mUxRChangeListener implemented in Step 2 above with the CarUxRestrictionsManager call mCarUxRestrictionsManager.registerListener():
    mCarUxRestrictionsManager.registerListener(mUxrChangeListener);
    mUxrChangeListener.onUxRestrictionsChanged(
    mCarUxRestrictionsManager.getCurrentCarUxRestrictions());
    

The completed block of sample code (created in Step 3 through Step 5) results in the listener receiving restriction changes when the drive state changes:

mCar = Car.createCar(context);
if (mCar == null) {
// handle car connection error
}

CarUxRestrictionsManager carUxRestrictionsManager = (CarUxRestrictionsManager)
mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);

mCarUxRestrictionsManager.registerListener(mUxrChangeListener);
mUxrChangeListener.onUxRestrictionsChanged(
mCarUxRestrictionsManager.getCurrentCarUxRestrictions());

CarUxRestrictions

The CarUxRestrictions object provides two types of information:

  1. Is there a current requirement to be Distraction Optimized?
  2. If so, what restrictions are currently in place?

Once CarUxRestrictions is obtained from either getCurrentUxRestrictions() or the listener callback, applications can now use the isRequiresDistractionOptimization() API to determine if Distraction Optimized is required. If this returns false, there is no requirement to be Distraction Optimized and an application can safely run any activity.

If optimization is required, then use the getActiveRestrictions() API to obtain the set of restrictions in place. This API returns an int, which is a bit mask of all the restrictions currently in effect. The set of restrictions currently notified is listed under CarUxRestrictions .

Note: Minor changes to the set of restrictions are anticipated to occur in the near future.

For example, if an application wants to determine if a restriction to play video exists, upon getting the CarUxRestrictions object, the application must check for the restriction:

int activeUxR = mCurrentCarUxRestrictions.getActiveRestrictions();
if ((activeUxR & CarUxRestrictions.UX_RESTRICTIONS_NO_VIDEO) != 0) {
      handleStopPlayingVideo();
}

DrivingState

CarDrivingStateManager presents the actual driving state of the vehicle (Parked, Idling, or Moving). CarDrivingStateManager APIs can be called similar to the CarUxRestrictionsManager. Applications can register a listener and/or get current driving state. The driving state is returned as CarDrivingStateEvent.

Similar to the CarUxRestrictionsManager APIs, clients can register a listener for the driving state using registerListener() and pass an implementation of the CarDrivingStateEventListener. On driving state changes, the onDrivingStateChanged() method will be called with the new CarDrivingStateEvent.

import android.car.Car;
/* For CarDrivingState */
import android.car.drivingstate.CarDrivingStateEvent;
import android.car.drivingstate.CarDrivingStateManager;

mDrivingStateManager = (CarDrivingStateManager) mCar.getCarManager(
       Car.CAR_DRIVING_STATE_SERVICE);
/* Register the listener (implemented below) */
mDrivingStateManager.registerListener(mDrivingStateEventListener);
/* While we wait for a change to be notified, query the current state */
mDrivingStateEvent = mDrivingStateManager.getCurrentCarDrivingState();

private final CarDrivingStateManager.CarDrivingStateEventListener
mDrivingStateEventListener =
       new CarDrivingStateManager.CarDrivingStateEventListener() {
   @Override
   public void onDrivingStateChanged(CarDrivingStateEvent event) {
       mDrivingStateEvent = event;
       /* handle the state change accordingly */
       handleDrivingStateChange();
   }
};

Testing

You can mimic the changing of gears and speed to change the driving state. Use an ADB shell command to inject vehicle events. This can be useful development and testing.

To simulate driving events:

  1. To set speed to 0:
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11600207 0
    
  2. To set gear to Parked (to simulate CarDrivingStateEvent pointing to PARKED):
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11400400 4
    
  3. To set gear to Drive, with speed still at 0 (to simulate CarDrivingStateEvent pointing to IDLING):
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11400400 8
    
  4. To set speed to 30 meters per second (to simulate CarDrivingStateEvent pointing to MOVING):
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11600207 30