使用汽车的驾驶状态和用户体验限制

本文将说明应用可以如何顺利转换到经过防分心优化 (DO) 的界面,并介绍如何使用汽车的驾驶状态以及相应的用户体验限制。 如需详细了解汽车用户体验 (UX) 限制规则,请参阅汽车用户体验限制,其中详细介绍了已驻车、空转和行车中这三种驾驶状态。

受众群体

本文所述内容的受众群体是有如下设计需求的开发者:想要设计的应用能够适用汽车的驾驶状态变化和相应的用户体验限制。

技术详情

CarDrivingStateManager

汽车的驾驶状态(已驻车、空转或行车中)通过车载硬件抽象层 (VHAL) 提供的传感器值推导得出。系统使用基本传感器信息(例如车辆速度和当前档位选择)来推导出当前的驾驶状态。

此信息通过 CarDrivingStateManager 提供给具有特权的客户端,CarDrivingStateManager 提供 @SystemApis,这意味着只有平台内部架构、捆绑的 APK(例如 SysUI 或设置)和特权 APK(例如 GMSCore)可以访问这些 API。这些 API 受特定于驾驶状态 android.car.permission.CAR_DRIVING_STATE 的权限保护。如果客户端需要访问驾驶状态信息,则必须请求此权限。

CarUxRestrictionsManager

根据驾驶状态显示界面的应用必须监听 CarUxRestrictionsManager,后者会抽象出从驾驶状态到用户体验限制的映射,这样应用就不需要根据不同的市场安全要求进行调整。

注意:这些 activity 必须标记为 DistractionOptimized,如有关防止驾驶员分心的准则中所述。如果未明确标记这些 activity,则 activity 会被阻止。

相反,应用会监控 CarUxRestrictionsManager 公开的限制,而不是由 CarDrivingStateManager 公开的绝对驾驶状态,以了解与界面或用户体验相关的所有信息。

代码示例

以下示例代码说明了应用如何监控用户体验限制:

  1. 导入汽车库软件包:
    import android.car.Car;
    /* For CarUxRestrictions */
    import android.car.drivingstate.CarUxRestrictions;
    import android.car.drivingstate.CarUxRestrictionsManager;
    
  2. 实现 CarUxRestrictionManager.OnUxRestrictionsChangedListener (mUxRChangeListener)。向 CarUxRestrictionsManager 注册此监听器后,当用户体验限制发生变化时,系统将调用此监听器。请根据需要对限制变化进行防分心优化:
    @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. 调用 Car API 以创建名为 mCar 的汽车实例,并连接到汽车服务:
    mCar = Car.createCar(context);
    if (mCar == null) {
    // handle car connection error
    }
    
  4. 调用 mCar.getCarManager() - mCarUxRestrictionsManager 以获取 CarUxRestrictionsManager
    CarUxRestrictionsManager carUxRestrictionsManager = (CarUxRestrictionsManager)
    mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
    
  5. 如需向 CarUxRestrictionsManager 注册在上文第 2 步中实现的 mUxRChangeListener,调用 mCarUxRestrictionsManager.registerListener()
    mCarUxRestrictionsManager.registerListener(mUxrChangeListener);
    mUxrChangeListener.onUxRestrictionsChanged(
    mCarUxRestrictionsManager.getCurrentCarUxRestrictions());
    

执行完示例代码块(在第 3 步至第 5 步中创建)后,监听器就会在驾驶状态发生变化时收到限制变化:

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

CarUxRestrictions 对象提供两类信息:

  1. 当前是否有要求需要进行防止分散注意力优化?
  2. 如果有,目前存在哪些限制?

getCurrentUxRestrictions() 或监听器回调获取 CarUxRestrictions 后,应用现在可以使用 isRequiresDistractionOptimization() API 来确定是否需要进行防分心优化。如果此 API 返回的是 false,则不存在需要进行防分心优化的要求,并且应用可安全地运行任何 activity。

如果需要进行优化,请使用 getActiveRestrictions() API 获取现有限制集。此 API 会返回一个整数值,这是当前生效的所有限制的位掩码。当前已知的限制集列在 CarUxRestrictions 下。

注意:预计会在不久的将来对限制集进行细微更改。

例如,如果应用需要确定是否存在视频播放限制,那么在获取 CarUxRestrictions 对象时,应用必须检查此限制:

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

DrivingState

CarDrivingStateManager 显示车辆的实际驾驶状态(已驻车、空转或行车中)。可以调用 CarDrivingStateManager API,这类似于调用 CarUxRestrictionsManager。 应用可以注册监听器和/或获取当前驾驶状态。驾驶状态以 CarDrivingStateEvent 的形式返回。

与 CarUxRestrictionsManager API 类似,客户端可以使用 registerListener() 为驾驶状态注册监听器,并传递 CarDrivingStateEventListener 的实现。如果驾驶状态发生变化,系统将使用新的 CarDrivingStateEvent 调用 onDrivingStateChanged() 方法。

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();
   }
};

测试

您可以通过模拟档位和速度的变化来更改驾驶状态。使用 adb shell 命令来注入车辆事件。这对开发和测试会很有帮助。

如需模拟驾驶事件,请执行以下操作:

  1. 如需将速度设置为 0,请运行以下命令:
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11600207 0
    
  2. 如需将档位设置为“停车”(模拟指向“PARKED”的 CarDrivingStateEvent),请运行以下命令:
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11400400 4
    
  3. 如需将档位设置为“行驶”,而使速度仍为 0(模拟指向“IDLING”的CarDrivingStateEvent),请运行以下命令:
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11400400 8
    
  4. 如需将速度设为每秒 30 米(模拟指向“MOVING”的 CarDrivingStateEvent),请运行以下命令:
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11600207 30