Consumir o estado de direção do carro e as restrições de UX

Esta página explica como os apps podem fazer a transição para interfaces do usuário otimizadas para distração (DO, na sigla em inglês). Ele descreve como consumir o estado de direção de um carro, bem como as restrições de experiência do usuário correspondentes. Para mais informações sobre as restrições de experiência do usuário (UX) do carro, consulte Restrições de experiência do usuário do carro, que detalha os três estados de direção: "Estacionado", "Em marcha lenta" e "Em movimento".

Público-alvo

Este conteúdo é fornecido para quem quer projetar apps que se adaptam a mudanças no estado de direção de um carro e às restrições de UX impostas.

Detalhes técnicos

CarDrivingStateManager

O estado de direção de um carro (estacionada, em marcha lenta ou em movimento) é derivado dos valores do sensor fornecidos pela camada de abstração de hardware do veículo (VHAL, na sigla em inglês). Informações básicas do sensor, como a velocidade do veículo e a seleção de marcha atual, são usadas para derivar o estado de direção atual do veículo.

CarDrivingStateEvent.

que fornece @SystemApis, o que significa que apenas plataformas internas, APKs agrupados (como SysUI ou Configurações) e APKs privilegiados (como) GMSCore podem acessar as APIs. As APIs são protegidas por permissões específicas para o estado de direção android.car.permission.CAR_DRIVING_STATE. Os clientes que precisam de acesso às informações do estado de direção precisam solicitar essa permissão.

CarUxRestrictionsManager

Os apps que mostram uma interface do usuário dependente do estado de direção precisam detectar CarUxRestrictionsManager, que abstrai o mapeamento do estado de direção para restrições de UX para que os apps não precisem se ajustar a diferentes requisitos de segurança do mercado.

Observação: essas atividades precisam ser marcadas como otimizadas para distração, conforme descrito nas diretrizes de distração do motorista. Se as atividades não forem marcadas corretamente, elas serão bloqueadas.

Em vez disso, os apps monitoram as restrições expostas pelo CarUxRestrictionsManager e não um estado de direção absoluto exposto pelo CarDrivingStateManager para qualquer coisa relacionada à interface do usuário ou à experiência do usuário.

Exemplo de código

O exemplo de código abaixo ilustra como um app monitora as restrições de UX:

  1. Importe os pacotes da biblioteca de carros:
    import android.car.Car;
    /* For CarUxRestrictions */
    import android.car.drivingstate.CarUxRestrictions;
    import android.car.drivingstate.CarUxRestrictionsManager;
  2. Implemente CarUxRestrictionManager.OnUxRestrictionsChangedListener (mUxRChangeListener). Esse listener, quando registrado com o CarUxRestrictionsManager, é chamado quando ocorre uma mudança nas restrições de UX. Processe as mudanças de restrição para otimizar a distração, conforme necessário:
    @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. Chame as APIs do carro para criar uma instância de carro chamada mCar e se conectar ao serviço de carro:
    mCar = Car.createCar(context);
    if (mCar == null) {
    // handle car connection error
    }
  4. Chame mCar.getCarManager() - mCarUxRestrictionsManager para receber o CarUxRestrictionsManager:
    CarUxRestrictionsManager carUxRestrictionsManager = (CarUxRestrictionsManager)
    mCar.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE);
  5. Para registrar mUxRChangeListener implementado na Etapa 2 acima com a chamada CarUxRestrictionsManager mCarUxRestrictionsManager.registerListener():
    mCarUxRestrictionsManager.registerListener(mUxrChangeListener);
    mUxrChangeListener.onUxRestrictionsChanged(
    mCarUxRestrictionsManager.getCurrentCarUxRestrictions());

O bloco de código de exemplo concluído (criado nas etapas 3 a 5) faz com que o listener receba mudanças de restrição quando o estado do drive muda:

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

O objeto CarUxRestrictions fornece dois tipos de informações:

  1. Há algum requisito atual para otimização de distrações?
  2. Em caso afirmativo, quais restrições estão em vigor?

Quando CarUxRestrictions é recebido de getCurrentUxRestrictions() ou do callback do listener, os apps agora podem usar a API isRequiresDistractionOptimization() para determinar se a otimização de distração é necessária. Se ele retornar false, não há requisito para ser otimizado para distração, e um app pode executar qualquer atividade com segurança.

Se a otimização for necessária, use a API getActiveRestrictions() para receber o conjunto de restrições em vigor. Essa API retorna um int, que é uma máscara de bits de todas as restrições em vigor. O conjunto de restrições atualmente notificado está listado em CarUxRestrictions.

Observação:mudanças menores no conjunto de restrições devem ocorrer em breve.

Por exemplo, se um app quiser determinar se existe uma restrição para reproduzir vídeos, ao receber o objeto CarUxRestrictions, ele precisará verificar a restrição:

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

DrivingState

O CarDrivingStateManager apresenta o estado de direção real do veículo (estacionado, em marcha lenta ou em movimento). As APIs CarDrivingStateManager podem ser chamadas de forma semelhante ao CarUxRestrictionsManager. Os apps podem registrar um listener ou receber o estado de direção atual. O estado de direção é retornado como CarDrivingStateEvent.

CarDrivingStateEvent.

muda, o método onDrivingStateChanged() é chamado com o novo 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();
   }
};

Teste

Você pode simular a mudança de marchas e a velocidade para mudar o estado de condução. Use um comando de shell do ADB para injetar eventos do veículo. Isso pode ser útil para desenvolvimento e testes.

Para simular eventos de direção:

  1. Para definir a velocidade como 0:
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11600207 0
  2. Para definir a marcha como "Estacionado" (para simular o CarDrivingStateEvent apontando para "PARKED"):
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11400400 4
  3. Para definir a engrenagem como "Drive", com a velocidade ainda em 0 (para simular o CarDrivingStateEvent apontando para IDLING):
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11400400 8
  4. Para definir a velocidade em 30 metros por segundo (para simular o CarDrivingStateEvent apontando para MOVING):
    adb shell dumpsys activity service com.android.car inject-vhal-event 0x11600207 30