API v1

Driver — Viagem Ativa

Android: /ui/driver/ · /ui/travels/ · TripFragment · TripManagementFragment

Módulo exclusivo para usuários com papel motorista. Exibe a viagem ativa com navegação assistida, botões de gerenciamento (iniciar, pausar, finalizar) e rastreamento de localização em tempo real.

Acesso restrito: Motoristas acessam apenas nav_trip_menu_driver / nav_trips_buttons na Home. Os demais módulos são bloqueados pela lógica de papel (user_role == "motorista").

Fragmentos do Módulo

FragmentoPacoteResponsabilidade
TripFragment/ui/travels/Tela principal da viagem ativa do motorista
TripManagementFragment/ui/travels/Ações de gerenciamento: iniciar, pausar, finalizar viagem
FragmentButtonsTravels/ui/travels/Botões rápidos de ação sobre a viagem
DriverTripViewModel/ui/travels/Lógica de negócio e chamadas à API

Viagem Ativa

O motorista visualiza apenas a viagem atribuída a ele. Os dados são buscados via GET /v1/trips?driver_id=... ou a viagem específica quando há uma em andamento. O fragment usa o DriverTripViewModel para gerenciar o estado.

Gerenciamento de Viagem

AçãoEndpointCondição
IniciarPOST /v1/trips/{id}/startViagem no status agendado/pendente
PausarPOST /v1/trips/{id}/pauseViagem em andamento
FinalizarPOST /v1/trips/{id}/finalizeViagem em andamento ou pausada

Rastreamento de Localização

Para usuários com papel motorista, o HomeFragment.onResume() solicita permissões de localização em foreground e background. A posição GPS é enviada ao backend periodicamente via serviço de background (FusedLocationProviderClient).

// Verificação de papel no onResume
if (userRole == "motorista") {
    requestForegroundLocationPermission()
    requestBackgroundLocationPermission()
}
Prominent Disclosure (Android 13+): antes de solicitar permissão de localização em background, o app exibe obrigatoriamente um diálogo explicativo exigido pelo Google Play. Esse dialog deve descrever claramente por que a localização em background é necessária.

Navegação Turn-by-Turn (NavigationManager1)

Atualizado junho/2026

O NavigationManager1 conduz a navegação assistida no mapa (OSMDroid) com instruções faladas via TextToSpeech. Cada instrução é um NavigationInstruction, montado a partir de rotogram_instruction da API. A rota e as alternativas vêm do endpoint consolidado GET /v1/rotograms/trip/{tripId}?_detail=true (ver Mapa). O campo type_id mapeia o ícone/voz da manobra:

type_idManobratype_idManobra
0 / 1continue (siga em frente)4 / 5destination
2 / -2turn_right / turn_left6roundabout
3 / -3turn_sharp_right / turn_sharp_left7 / -7keep_right / keep_left
8turn_around (retorno em U)valores negativos = à esquerda

As coordenadas da instrução vêm como [lng, lat] (ordem GeoJSON) — latitude = coordinates[1], longitude = coordinates[0].

Cache Offline da Sessão (DriverSessionCache)

Atualizado junho/2026

O DriverSessionCache é o equivalente Android do DriverCacheManager do iOS: guarda, num único blob por tripId_routeId, tudo que o motorista precisa para continuar a viagem sem rede.

Lacuna que isto fecha: antes, no Android, só a geometria da rota + coordenadas (e a info textual, via worker TripAtributtedWorkService) sobreviviam offline. Instruções turn-by-turn, rotas alternativas e pontos de parada se perdiam. Agora tudo é persistido junto.
Campo do blobConteúdo
mainGeoJsonGeometria da rota principal (rotogram_route com coordinates)
mainInstructionsInstruções turn-by-turn da rota principal
alternativesRotas alternativas — pontos + instruções de cada uma
stopPointsPontos de parada (id, nome, lat/lng, categoria)
coordStart / coordDestinationCoordenadas de origem e destino
routeName, startName, destinationNameTextos da viagem
forecastStart / forecastEndPrevisões de início/fim
createdByRoute, createdByTrip, driverNamesCriadores e motoristas

Cada save* persiste o blob inteiro (mesmo padrão do iOS), então a sessão no disco é sempre consistente. A chave (driver_session_{tripId}_{routeId}, prefs driver_session_cache) é por viagem + rota para não misturar dados entre viagens que reusem a mesma rota. load() retorna false se não há cache para a viagem/rota.

Helpers relacionados desta entrega: TripCacheCleaner (limpeza de cache de viagens) e NavigationManager1 (consome as instruções cacheadas para navegar offline).

Paridade iOS: mesma estrutura de blob consolidado no DriverCacheManager. O objetivo é que Android e iOS tenham exatamente o mesmo comportamento offline na viagem do motorista.
Pontos autorizados e áreas de risco no mapa: além do cache, o mapa do motorista renderiza os pontos autorizados e os polígonos de área de risco da viagem, buscados por fetchStopPointsapplyStopPoints/parseRiskArea (models RiskAreaData/riskAreasById) via GET /trip/{tripId}/rotogram (mesma base STAGING do detalhe da entrega). A renderização detalhada está em Mapa.

Comprovação de Entregas (canhotos)

Atualizado junho/2026 /ui/driver/ · helpers/DeliveryProofUi.kt

Fluxo em que o motorista anexa o canhoto (comprovante) de cada entrega da rota. O backend é real: os canhotos enviados ficam no array delivery_receipts de cada entrega (deliveries[]) retornado pelo endpoint consolidado GET /v1/trip/{id}; o envio é um POST multipart. Existem três pontos de entrada para o mesmo conjunto de telas/render.

Pontos de entrada

OrigemTela abertaGating
Card "Minhas Viagens" → botão Entregas (item_trip.xml / TripAdapter)PendingDeliveriesFragment (lista de entregas da viagem)Botão só aparece com permissão 435. Com 435, o card NÃO navega ao toque — só os botões Mapa/Entregas.
Mapa do motorista → seção "Entregas da rota" no bottom sheet de detalhes (DriverTripFragment)Somente leitura — status ✓/aguardando + nº de canhotos. Sem anexação aqui.Sem gating extra (faz parte do detalhe da viagem).
Home → botão "Entregas Pendentes" (HomeAdapter id=11)PendingDeliveriesFragment sem tripId → lista vazia + empty stateVisibilidade liberada para motorista/"411" em NavigationManagerPerms.

Telas e render compartilhado

Classe / arquivoResponsabilidade
PendingDeliveriesFragment + PendingDeliveriesViewModelNewLista de entregas da viagem (cards item_delivery_card.xml): loja, nome/endereço, badge canhoto (✓ verde / ✗ vermelho), chip ROTA, "N canhotos enviados", pill horário/"Aguardando". Recarrega no onResume() para refletir envios.
DeliveryDetailFragment + DeliveryDetailViewModelNewDetalhe de uma entrega: mapa/ponto/endereço, telefones, miniaturas dos canhotos já enviados e anexação por câmera in-app (CanhotoCameraActivity) ou galeria (GetContent), com upload automático.
helpers/DeliveryProofUi.ktRender compartilhado (models DeliveryUi/RouteDeliveryUi, populate da seção "Entregas da rota", routeProvenLabel, confirmReplace). Reusado pelo mapa e pelas telas de entrega.

Endpoints

GET/v1/trip/{id}
Endpoint consolidado da viagem. Cada item de deliveries[] traz delivery_location (id, name, address, telefones) e delivery_receipts[] (canhotos já enviados). Fonte única tanto da lista quanto da seção do mapa quanto do estado "enviado" do detalhe.
GET/trip/{tripId}/rotogram
Endpoint dedicado a pontos — usado no detalhe da entrega (DeliveryDetailViewModelNew.getPoint) para resolver o ponto (lat/lng, endereço) por delivery_location.id. A resposta traz data[].deliveries[]; filtramos type == "delivery" e o id selecionado. Mesma chamada dos pontos autorizados/áreas de risco do mapa.
Aponta para STAGING (nginx), não para produção. A base deste endpoint é http://nginx.surubim.monisat.online/v1 (BASE_URL em DeliveryDetailViewModelNew), HTTP e fora de produção — pendente troca para https://api.monisystem.com/v1 (PROD_URL) quando o endpoint subir. O envio de canhotos (POST abaixo) já usa a base de produção.
POST/v1/trip/{tripId}/delivery-receipts
Envio do canhoto, multipart/form-data. Campos: delivery_location_id, lat, lng, photo_taken_at e files (repetido por arquivo). Após sucesso o ViewModel refaz GET /v1/trip/{id} e atualiza a UI sem reabrir a tela.

Campos de delivery_receipts[]

CampoConteúdo
image_pathCaminho do arquivo no storage
image_urlURL S3 pré-assinada (validade ~1h) — usada para baixar a miniatura
photo_taken_at / registered_atTimestamp da captura / do registro no servidor
user_idMotorista que enviou
location {lat,lng}Posição no momento do envio
Chave correta = delivery_receipts. Versões anteriores do parse liam receipts/canhotos e nunca batiam — o badge nunca ficava verde. Corrigido em PendingDeliveriesViewModelNew e DriverTripViewModelNew. Não há campo de "total esperado" de canhotos por entrega, então não há contagem de pendentes por documento — só "tem canhoto" vs "aguardando".

Câmera do canhoto (in-app)

Ao tocar em "Adicionar mais"/"Anexar Canhoto", o motorista escolhe num bottom sheet entre câmera e galeria. A opção câmera não usa mais o app de câmera do sistema: abre a câmera custom in-app CanhotoCameraActivity (CameraX), com helpers/CameraOverlayView.kt desenhando um overlay estilo scanner — a tela escurece (~65%) e abre uma moldura deitada (proporção de canhoto) centralizada, para o motorista enquadrar o documento. A galeria continua via GetContent.

EtapaComportamento
Diálogo de instruçãomaybeShowCanhotoInstructions mostra as orientações antes de abrir a câmera; um "não mostrar de novo" é persistido na pref show_canhoto_instructions.
CapturaCanhotoCameraActivity abre o preview do CameraX com o overlay/moldura e o botão de captura no rodapé.
ConferênciaApós capturar, a foto cobre a câmera com o título "A foto ficou boa?" e as ações Refazer / Usar. Só ao confirmar ("Usar") a Activity devolve RESULT_OK e a imagem é enviada; "Refazer" (ou o botão voltar) retorna à câmera sem cancelar.

Substituir e Remover Canhoto

Substituir: com ≥1 canhoto já enviado, o botão do detalhe vira "Substituir Canhoto". O toque abre um diálogo de confirmação (dialog_replace_doc.xml via DeliveryProofUi.confirmReplace) avisando que o canhoto atual permanece no histórico; ao confirmar, oculta os canhotos antigos e abre o seletor câmera/galeria. Lista de canhotos vazia = entrega pendente, botão "Anexar Canhoto".

Remover: cada canhoto enviado aparece numa lista com data/hora e uma lixeira. A lixeira (hideReceipt) apenas remove da lista visual — a imagem permanece salva no sistema (banco); o ocultamento é persistido localmente (hiddenPaths) para não reaparecer ao recarregar. O controle é gated pela flag SHOW_REMOVE em DeliveryDetailFragment (hoje false, aguardando a inativação/ocultação de documento no backend).

Sem NF e sem "código único" nesta tela. A comprovação de entrega é feita exclusivamente por foto de canhoto. A NF não é mais exibida aqui (DriverTripViewModelNew: "NF não é mais exibida aqui") e não existe nenhum campo de "código único"/código de confirmação de entrega.
Imagens sem lib externa: o projeto não usa Glide/Coil/Picasso. As miniaturas são baixadas via HttpURLConnection + BitmapFactory a partir da image_url pré-assinada.
Pendências: o estado das entregas no mapa ainda não é persistido em DriverSessionCache (sem offline aqui); confirmar com o backend se a substituição mantém o canhoto anterior no histórico.

ViewModels e Arquitetura

ClasseResponsabilidade
TripViewModelEstado e dados da viagem ativa
TripViewModelNewVersão migrada para API v1
DriverTripViewModelAções específicas de motorista (start/pause/finalize)
TripViewModelFactoryFactory para injeção de dependências no ViewModel

SharedPreferences relevantes

NomeChaveUso
user_iduser_rolePapel do usuário: "motorista" habilita o módulo
driverdriverBoolean que controla exibição de botões de motorista em Config
jwt_tokensjwt_tokenBearer JWT para chamadas v1
driver_session_cachedriver_session_{tripId}_{routeId}Blob offline consolidado da sessão de viagem (Gson)