APIs do Android 4.4

API de nível: 19

O Android 4.4 (KITKAT) é uma nova versão da plataforma Android que oferece novos recursos para usuários e desenvolvedores de apps. Este documento fornece uma introdução às principais novas APIs.

Como desenvolvedor de apps, faça o download da imagem do sistema do Android 4.4 e da plataforma do SDK no SDK Manager o quanto antes. Se você não tiver um dispositivo com o Android 4.4 para testar o app, use a imagem do sistema do Android 4.4 para testar o app no Android Emulator. Em seguida, crie seus apps na plataforma Android 4.4 para começar a usar as APIs mais recentes.

Atualização do nível da API

Para otimizar melhor o app para dispositivos com Android 4.4, defina targetSdkVersion como "19", instale-o em uma imagem do sistema do Android 4.4, teste e publique uma atualização com essa mudança.

Você pode usar APIs no Android 4.4 e, ao mesmo tempo, oferecer suporte a versões mais antigas, adicionando condições ao código que verificam o nível da API do sistema antes de executar APIs sem suporte da minSdkVersion. Para saber mais sobre como manter a compatibilidade com versões anteriores, leia Compatibilidade com diferentes versões da plataforma.

Para mais informações sobre como os níveis da API funcionam, leia O que é um nível da API?.

Mudanças de comportamento importantes

Caso você já tenha publicado um app para Android, saiba que ele pode ser afetado pelas mudanças do Android 4.4.

Se seu aplicativo lê dados em armazenamento externo...

O app não pode ler arquivos compartilhados no armazenamento externo ao ser executado no Android 4.4, a menos que tenha a permissão READ_EXTERNAL_STORAGE. Ou seja, os arquivos no diretório retornado por getExternalStoragePublicDirectory() não podem mais ser acessados sem permissão. No entanto, se você precisar acessar apenas os diretórios específicos do app, fornecidos pelo getExternalFilesDir(), não vai precisar da permissão READ_EXTERNAL_STORAGE.

Se seu aplicativo usa o WebView...

Seu app pode se comportar de maneira diferente ao ser executado no Android 4.4, especialmente quando você atualiza a targetSdkVersion para a versão "19" ou mais recente.

O código da classe WebView e das APIs relacionadas foi atualizado para ser baseado em um snapshot moderno do código-fonte do Chromium. Isso traz uma variedade de melhorias de desempenho, suporte a novos recursos HTML5 e suporte à depuração remota do conteúdo de WebView. O escopo desse upgrade significa que, se o app usa o WebView, o comportamento dele pode ser afetado em alguns casos. Embora as mudanças de comportamento conhecidas sejam documentadas e afetem principalmente o app quando você atualiza a targetSdkVersion para "19" ou mais recente, o novo WebView opera no "modo quirks" para fornecer algumas funcionalidades legadas em apps destinados ao nível 18 da API e versões anteriores. É possível que seu app dependa de comportamentos desconhecidos da versão anterior do WebView.

Portanto, se o app já usa o WebView, é importante testar o Android 4.4 assim que possível e consultar Como migrar para o WebView no Android 4.4 para saber como o app pode ser afetado quando você atualizar a targetSdkVersion para a versão "19" ou mais recente.

Se seu aplicativo usa o AlarmManager...

Quando você define a targetSdkVersion do app como "19" ou mais recente, os alarmes criados usando set() ou setRepeating() são imprecisos.

Para aumentar a eficiência do consumo de energia, agora o Android agrupa alarmes que ocorrem em momentos razoavelmente similares de todos os aplicativos para que o sistema "desperte" o dispositivo uma vez só, em vez de diversas vezes para tratar de cada alarme.

Se o alarme não estiver associado a uma hora exata do relógio, mas ainda for importante que ele seja invocado em um intervalo de tempo específico (como entre 14h e 16h), você poderá usar o novo método setWindow(), que aceita um horário "mais antecipado" para o alarme e uma "janela" depois do horário mais cedo em que o sistema pode invocar o alarme.

Se o alarme precisar ser fixado em uma hora exata do relógio (por exemplo, para um lembrete de evento da agenda), use o novo método setExact().

Esse comportamento de agrupamento inexato aplica-se somente a aplicativos atualizados. Se você definiu a targetSdkVersion como "18" ou uma versão anterior, seus alarmes continuarão se comportando como na versão anterior ao serem executados no Android 4.4.

Se seu aplicativo sincroniza dados usando o ContentResolver...

Quando você define a targetSdkVersion do app como "19" ou mais recente, a criação de uma sincronização com addPeriodicSync() realiza as operações de sincronização em um intervalo flexível padrão de aproximadamente 4% do período especificado. Por exemplo, se a frequência da sua enquete for 24 horas, a operação de sincronização pode ocorrer em uma janela de tempo de cerca de uma hora todos os dias, em vez de exatamente na mesma hora.

Para especificar seu próprio intervalo flexível para operações de sincronização, comece a usar o novo método requestSync(). Para ver mais detalhes, consulte a seção abaixo sobre Adaptadores de sincronização.

Esse comportamento de intervalo flexível aplica-se somente a aplicativos atualizados. Se você definiu o targetSdkVersion como "18" ou anterior, as solicitações de sincronização existentes continuarão se comportando como nas versões anteriores ao serem executadas no Android 4.4.

Estrutura de impressão

Agora o Android contém uma estrutura completa que permite que os usuários imprimam qualquer documento usando uma impressora conectada por Wi-Fi, Bluetooth ou outros serviços. O sistema lida com a operação entre um aplicativo que deseja imprimir um documento e os serviços que fornecem trabalhos de impressão a uma impressora. O framework android.print fornece todas as APIs necessárias para especificar um documento de impressão e entregá-lo ao sistema para impressão. De quais APIs você realmente precisa para determinado trabalho de impressão depende do conteúdo.

Impressão de conteúdo genérico

Se você quiser mostrar conteúdo da interface como um documento, primeiro crie uma subclasse de PrintDocumentAdapter. Nessa classe, é necessário implementar alguns métodos de callback, incluindo onLayout() para estabelecer o layout com base nas propriedades de impressão fornecidas e onWrite() para serializar o conteúdo de impressão em um ParcelFileDescriptor.

Para gravar seu conteúdo no ParcelFileDescriptor, é necessário transmitir um PDF a ele. As novas APIs PdfDocument oferecem uma maneira conveniente de fazer isso, fornecendo um Canvas de getCanvas(), em que você pode desenhar seu conteúdo para impressão. Em seguida, grave o PdfDocument no ParcelFileDescriptor usando o método writeTo().

Depois de definir a implementação de PrintDocumentAdapter, você pode executar trabalhos de impressão mediante solicitação do usuário usando o método PrintManager, print(), que usa o PrintDocumentAdapter como um dos argumentos.

Impressão de imagens

Se você quiser imprimir apenas uma foto ou outro bitmap, as APIs de assistente da biblioteca de suporte fazem todo o trabalho para você. Basta criar uma nova instância de PrintHelper, definir o modo de escalonamento com setScaleMode() e transmitir Bitmap para printBitmap(). Pronto. A biblioteca lida com todas as interações restantes com o sistema para fornecer o bitmap à impressora.

Criação de serviços de impressão

Como OEM de impressora, você pode usar o framework android.printservice para oferecer interoperabilidade com suas impressoras em dispositivos Android. É possível criar e distribuir serviços de impressão como APKs, que os usuários podem instalar nos dispositivos. Um app de serviço de impressão opera principalmente como um serviço headless ao subclassificar a classe PrintService, que recebe trabalhos de impressão do sistema e os comunica às impressoras usando os protocolos adequados.

Para saber mais sobre como imprimir o conteúdo do seu app, leia Como imprimir conteúdo.

Provedor de SMS

O provedor de conteúdo Telephony (o "Provedor de SMS") permite que os apps leiam e gravem mensagens SMS e MMS no dispositivo. Incluem-se tabelas de mensagens de SMS e MMS recebidas, de rascunho, enviadas, pendentes, entre outras.

A partir do Android 4.4, as configurações do sistema permitem que os usuários selecionem um "aplicativo de SMS padrão". Depois de selecionado, somente o app de SMS padrão poderá gravar no provedor de SMS e apenas o app de SMS padrão receberá a transmissão SMS_DELIVER_ACTION quando o usuário receber um SMS ou a transmissão WAP_PUSH_DELIVER_ACTION quando o usuário receber um MMS. O aplicativo de SMS padrão é responsável por gravar detalhes no Provedor de SMS quando ele recebe ou envia uma nova mensagem.

Outros apps que não estiverem selecionados como o app de SMS padrão só poderão ler o provedor de SMS, mas também poderão ser notificados quando um novo SMS chegar. Para isso, eles ouvem a transmissão SMS_RECEIVED_ACTION, que é uma transmissão não cancelável que pode ser entregue a vários apps. Essa transmissão visa os aplicativos que, embora não selecionados como o aplicativo de SMS padrão, precisam ler mensagens recebidas especiais, como para realizar verificação do número do telefone.

Para mais informações, leia a postagem do blog Como preparar seus apps de SMS para o KitKat (em inglês).

Redes sem fio e conectividade

Emulação de cartão host

Os aplicativos Android agora podem emular cartões NFC ISO14443-4 (ISO-DEP) que usam APDUs para troca de dados (conforme especificado em ISO7816-4). Isso permite que um dispositivo com NFC integrado e Android 4.4 emule diversos cartões NFC ao mesmo tempo, além de permitir que um terminal de pagamento NFC ou outro leitor NFC inicie uma transação com o cartão NFC em questão com base no identificador do aplicativo (AID).

Se você quiser emular um cartão NFC que use esses protocolos no app, crie um componente de serviço com base na classe HostApduService. Se o app usar um elemento de segurança para a emulação de cartão, será necessário criar um serviço com base na classe OffHostApduService, que não estará diretamente envolvida nas transações, mas será necessária para registrar os AIDs que precisam ser processados pelo elemento de segurança.

Para mais informações, leia o guia Emulação de cartão NFC.

Modo de leitor NFC

Um novo modo de leitor NFC permite que uma atividade restrinja todas as atividades de NFC para somente ler os tipos de tag em que a atividade está interessada quando está em primeiro plano. Você pode ativar o modo leitor para sua atividade com enableReaderMode(), fornecendo uma implementação de NfcAdapter.ReaderCallback que recebe um callback quando novas tags são detectadas.

Esse novo recurso, junto com a emulação de cartão host, permite que o Android opere em ambas as extremidades de uma interface de pagamento móvel: um dispositivo opera como o terminal de pagamento (aquele que executa uma atividade no modo leitor) e outro opera como cliente de pagamento (um dispositivo que emula um cartão NFC).

Transmissores infravermelhos

Ao executar em um dispositivo que inclua um transmissor infravermelho (IR), agora é possível transmitir sinais IR usando as APIs ConsumerIrManager. Para receber uma instância de ConsumerIrManager, chame getSystemService() com CONSUMER_IR_SERVICE como argumento. É possível consultar as frequências de IR compatíveis com o dispositivo com getCarrierFrequencies() e transmitir sinais transmitindo a frequência e o padrão de sinal desejados com transmit().

Primeiro, verifique se um dispositivo inclui um transmissor IR chamando hasIrEmitter(). No entanto, se o app for compatível apenas com dispositivos que tenham um, inclua um elemento <uses-feature> no manifesto para "android.hardware.consumerir" (FEATURE_CONSUMER_IR).

Multimídia

Reprodução adaptativa

A compatibilidade com reprodução de vídeo adaptável agora está disponível com as APIs MediaCodec, permitindo mudança perfeita na resolução durante a reprodução em uma Surface. É possível alimentar os frames de entrada do decodificador de uma nova resolução, e a resolução dos buffers de saída mudar sem uma lacuna significativa.

Você pode ativar a reprodução adaptativa adicionando duas chaves a MediaFormat que especificam a resolução máxima exigida pelo app do codec: KEY_MAX_WIDTH e KEY_MAX_HEIGHT. Depois de adicioná-las ao MediaFormat, transmita o MediaFormat para a instância do MediaCodec com configure().

O codec fara uma transição entre resoluções que tenham valores iguais ou inferiores a esses especificados de forma muito suave. O codec pode ainda funcionar com resoluções com valores superiores aos máximos especificados (desde que estejam dentro dos limites dos perfis compatíveis), mas as transições para resoluções maiores pode não ser suave.

Para alterar a resolução durante a decodificação de vídeo H.264, continue enfileirando quadros usandoMediaCodec.queueInputBuffer(), mas não deixe de fornecer os novos valores de Conjunto de parâmetros de sequência (SPS) e Conjunto de parâmetros de imagem (PPS) juntos com o quadro Atualização instantânea do decodificador (IDR) em um único buffer.

No entanto, antes de tentar configurar seu codec para reprodução adaptativa, é necessário verificar se o dispositivo oferece suporte à reprodução adaptativa chamando isFeatureSupported(String) com FEATURE_AdaptivePlayback.

Observação:o suporte para reprodução adaptativa é específico do fornecedor. Alguns codecs podem exigir mais memória para maiores sugestões de resolução. Assim, você deve definir os máximos da resolução com base no material de origem que estiver decodificando.

Marcações de data e hora de áudio sob demanda

Para facilitar a sincronização entre áudio e vídeo, a nova classe AudioTimestamp fornece detalhes da linha do tempo sobre um "frame" específico em um stream de áudio processado por AudioTrack. Para acessar o carimbo de data/hora mais recente disponível, instancie um objeto AudioTimestamp e transmita-o para getTimestamp(). Se a solicitação do carimbo de data/hora for bem-sucedida, a instância AudioTrack será preenchida com uma posição em unidades de frames, além do tempo estimado em que esse frame foi apresentado ou foi confirmado.

Você pode usar o valor de nanoTime no AudioTimestamp (que é monotônico) para encontrar o frame de vídeo associado mais próximo em comparação com framePosition. Assim, você pode remover, duplicar ou interpolar frames de vídeo para corresponder ao áudio. Como alternativa, é possível determinar o tempo delta entre o valor de nanoTime e o tempo esperado de um frame de vídeo futuro (considerando a taxa de amostragem) para prever qual frame de áudio é esperado para o mesmo momento que um frame de vídeo.

Leitor de imagens de superfície

A nova API ImageReader fornece acesso direto aos buffers de imagem conforme eles são renderizados em um Surface. Você pode adquirir um ImageReader com o método estático newInstance(). Em seguida, chame getSurface() para criar um novo Surface e enviar os dados de imagem com um produtor como MediaPlayer ou MediaCodec. Para receber uma notificação quando novas imagens estiverem disponíveis, implemente a interface ImageReader.OnImageAvailableListener e registre-a com setOnImageAvailableListener().

Agora, enquanto você renderiza conteúdo no Surface, o ImageReader.OnImageAvailableListener recebe uma chamada para onImageAvailable() conforme cada novo frame de imagem é disponibilizado, fornecendo o ImageReader correspondente. Você pode usar o ImageReader para coletar os dados de imagem do frame como um objeto Image chamando acquireLatestImage() ou acquireNextImage().

O objeto Image fornece acesso direto ao carimbo de data/hora, ao formato, às dimensões e aos dados de pixel da imagem em um ByteBuffer. No entanto, para que a classe Image interprete as imagens, elas precisam ser formatadas de acordo com um dos tipos definidos por constantes em ImageFormat ou PixelFormat.

Medição de pico e RMS

Agora é possível consultar o pico e o RMS do stream de áudio atual de Visualizer criando uma nova instância de Visualizer.MeasurementPeakRms e transmitindo-a para getMeasurementPeakRms(). Quando você chama esse método, os valores de pico e RMS da Visualizer.MeasurementPeakRms especificada são definidos como os últimos valores medidos.

Atenuador de ruído

O LoudnessEnhancer é uma nova subclasse da AudioEffect que permite aumentar o volume audível da MediaPlayer ou da AudioTrack. Isso pode ser especialmente útil em conjunto com o novo método getMeasurementPeakRms() mencionado acima, para aumentar o volume das faixas de áudio falado enquanto outra mídia está sendo reproduzida.

Controladores remotos

O Android 4.0 (nível 14 da API) introduziu as APIs RemoteControlClient, que permitem que apps de música consumam eventos de controladores de mídia de clientes remotos, como controles de mídia na tela de bloqueio. Agora, as novas APIs RemoteController permitem que você crie seu próprio controle remoto, possibilitando a criação de novos apps e periféricos inovadores que podem controlar a reprodução de qualquer app de música integrado ao RemoteControlClient.

Para criar um controle remoto, você pode implementar sua interface do usuário da maneira que quiser, mas, para enviar os eventos de botão de mídia ao app de música do usuário, você precisa criar um serviço que estenda a classe NotificationListenerService e implemente a interface RemoteController.OnClientUpdateListener. É importante usar o NotificationListenerService como base, porque ele fornece as restrições de privacidade adequadas, que exigem que os usuários ativem seu app como um listener de notificações nas configurações de segurança do sistema.

A classe NotificationListenerService inclui alguns métodos abstratos que você precisa implementar. No entanto, se você só quiser lidar com os eventos de controles de mídia para processar a reprodução de mídia, deixe a implementação deles vazias e se concentre nos métodos RemoteController.OnClientUpdateListener.

Classificação de controladores remotos

O Android 4.4 se baseia nos recursos existentes para clientes de controle remoto (apps que recebem eventos de controle de mídia com o RemoteControlClient) adicionando a capacidade de os usuários classificarem a faixa atual no controle remoto.

A nova classe Rating encapsula informações sobre uma avaliação de usuários. Uma nota é definida pelo estilo (RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS, RATING_5_STARS ou RATING_PERCENTAGE) e pelo valor apropriado para esse estilo.

Para que os usuários possam classificar suas trilhas por um controlador remoto:

Para receber um callback quando o usuário mudar a nota do controlador remoto, implemente a nova interface RemoteControlClient.OnMetadataUpdateListener e transmita uma instância para setMetadataUpdateListener(). Quando o usuário muda a nota, o RemoteControlClient.OnMetadataUpdateListener recebe uma chamada para onMetadataUpdate(), transmitindo RATING_KEY_BY_USER como a chave e um objeto Rating como o valor.

Legendas

O VideoView agora oferece suporte a faixas de legenda WebVTT ao reproduzir vídeos HTTP Live Stream (HLS), exibindo a faixa de legenda de acordo com as preferências de legenda que o usuário definiu nas configurações do sistema.

Você também pode fornecer VideoView com faixas de legenda WebVTT usando o método addSubtitleSource(). Esse método aceita um InputStream que carrega os dados da legenda e um objeto MediaFormat que especifica o formato dos dados da legenda, que você pode especificar usando createSubtitleFormat(). Essas legendas também aparecem sobre o vídeo de acordo com as preferências do usuário.

Se você não usar VideoView para exibir o conteúdo de vídeo, faça com que a sobreposição de legenda corresponda o máximo possível às preferências de legenda do usuário. Uma nova API CaptioningManager permite consultar as preferências de legenda do usuário, incluindo estilos definidos por CaptioningManager.CaptionStyle, como família tipográfica e cor. Caso o usuário ajuste algumas preferências depois que o vídeo já tiver começado, detecte as mudanças registrando uma instância de CaptioningManager.CaptioningChangeListener para receber um callback quando qualquer uma das preferências mudar e atualize as legendas conforme necessário.

Animação e gráficos

Cenas e transições

O novo framework android.transition fornece APIs que facilitam animações entre diferentes estados da interface do usuário. Um recurso importante é a capacidade de definir estados distintos da interface, conhecidos como "cenas", criando um layout separado para cada um. Quando quiser animar de uma cena para outra, execute uma "transição", que calcula a animação necessária para mudar o layout da cena atual para a próxima.

Para realizar a transição entre duas cenas, você geralmente precisa realizar o seguinte:

  1. Especifique o ViewGroup que contém os componentes de interface que você quer mudar.
  2. Especifique o layout que representa o resultado final da mudança (a próxima cena).
  3. Especifique o tipo de transição que deve animar a mudança de layout.
  4. Execute a transição.

É possível usar um objeto Scene para realizar as etapas 1 e 2. Uma Scene contém metadados que descrevem as propriedades de um layout necessárias para realizar uma transição, incluindo a visualização mãe e o layout da cena. Você pode criar uma Scene usando um construtor de classe ou o método estático getSceneForLayout().

Em seguida, use o TransitionManager para concluir as etapas 3 e 4. Uma maneira é transmitir o Scene para o método estático go(). Isso encontra a visualização mãe da cena no layout atual e realiza uma transição nas visualizações filhas para chegar ao layout definido pelo Scene.

Como alternativa, não é necessário criar um objeto Scene, mas você pode chamar beginDelayedTransition(), especificando um ViewGroup que contenha as visualizações que quer mudar. Depois adicione, remova ou reconfigure as visualizações que quiser. Depois que o sistema aplicar as mudanças conforme o necessário, uma transição começará a animar todas as visualizações afetadas.

Para ter mais controle, você pode definir conjuntos de transições que precisam ocorrer entre cenas predefinidas, usando um arquivo XML no diretório res/transition/ do seu projeto. Dentro de um elemento <transitionManager>, especifique uma ou mais tags <transition> que especifiquem uma cena (uma referência a um arquivo de layout) e a transição a ser aplicada ao entrar e/ou sair dessa cena. Em seguida, infle esse conjunto de transições usando inflateTransitionManager(). Use o TransitionManager retornado para executar cada transição com transitionTo(), transmitindo um Scene que é representado por uma das tags <transition>. Você também pode definir conjuntos de transições de maneira programática com as APIs TransitionManager.

Ao especificar uma transição, você pode usar vários tipos predefinidos definidos por subclasses de Transition, como Fade e ChangeBounds. Se você não especificar um tipo de transição, o sistema vai usar AutoTransition por padrão, que esmaece, move e redimensiona as visualizações automaticamente conforme necessário. Além disso, você pode criar transições personalizadas estendendo qualquer uma dessas classes para executar as animações como quiser. Uma transição personalizada pode rastrear as alterações de propriedade que você quiser e criar as animações que quiser com base nelas. Por exemplo, você pode fornecer uma subclasse de Transition que detecte mudanças na propriedade "rotation" de uma visualização e, em seguida, animar as mudanças.

Para mais informações, consulte a documentação do TransitionManager.

Pausa do animador

As APIs Animator agora permitem pausar e retomar uma animação em andamento com os métodos pause() e resume().

Para monitorar o estado de uma animação, implemente a interface Animator.AnimatorPauseListener, que fornece callbacks quando uma animação é pausada e retomada: pause() e resume(). Em seguida, adicione o listener a um objeto Animator com addPauseListener().

Como alternativa, você pode subclassificar a classe abstrata AnimatorListenerAdapter, que agora inclui implementações vazias para os callbacks de pausa e retomada definidos por Animator.AnimatorPauseListener.

Bitmaps reutilizáveis

Agora você pode reutilizar qualquer bitmap mutável em BitmapFactory para decodificar qualquer outro, mesmo quando o novo bitmap tiver um tamanho diferente, desde que a contagem de bytes resultante do bitmap decodificado (disponível em getByteCount()) seja menor ou igual à contagem de bytes alocada do bitmap reutilizado (disponível em getAllocationByteCount()) Para mais informações, consulte inBitmap.

As novas APIs para Bitmap permitem reconfiguração semelhante para reutilização fora de BitmapFactory (para geração manual de bitmap ou lógica de decodificação personalizada). Agora você pode definir as dimensões de um bitmap com os métodos setHeight() e setWidth() e especificar um novo Bitmap.Config com setConfig() sem afetar a alocação de bitmap. O método reconfigure() também oferece uma maneira conveniente de combinar essas mudanças com uma chamada.

No entanto, não reconfigure um bitmap que esteja sendo usado atualmente pelo sistema de visualização, porque o buffer de pixels subjacente não será remapeado de maneira previsível.

Conteúdo do usuário

Estrutura de acesso ao armazenamento

Em versões anteriores do Android, se você quiser que seu app recupere um tipo específico de arquivo de outro app, ele precisa invocar uma intent com a ação ACTION_GET_CONTENT. Essa ação ainda é a maneira adequada de solicitar um arquivo que você quer importar para o app. No entanto, o Android 4.4 introduz a ação ACTION_OPEN_DOCUMENT, que permite ao usuário selecionar um arquivo de um tipo específico e conceder ao app acesso de leitura de longo prazo (possivelmente com acesso de gravação) sem importar o arquivo para o app.

Se você está desenvolvendo um app que fornece serviços de armazenamento de arquivos (como um serviço de salvamento na nuvem), pode participar dessa interface unificada para coletar arquivos, implementando um provedor de conteúdo como uma subclasse da nova classe DocumentsProvider. A subclasse de DocumentsProvider precisa incluir um filtro de intent que aceite a ação PROVIDER_INTERFACE ("android.content.action.DOCUMENTS_PROVIDER"). Em seguida, implemente os quatro métodos abstratos no DocumentsProvider:

queryRoots()
Isso retornará um Cursor que descreve todos os diretórios raiz do armazenamento de documentos, usando colunas definidas em DocumentsContract.Root.
queryChildDocuments()
Isso retornará uma Cursor que descreve todos os arquivos no diretório especificado, usando colunas definidas em DocumentsContract.Document.
queryDocument()
Isso retornará uma Cursor que descreve o arquivo especificado, usando colunas definidas em DocumentsContract.Document.
openDocument()
Isso retornará um ParcelFileDescriptor que representa o arquivo especificado. O sistema chama esse método depois que o usuário seleciona um arquivo e o app cliente solicita acesso a ele chamando openFileDescriptor().

Para ver mais informações, consulte o guia Framework de acesso ao armazenamento.

Acesso a armazenamento externo

Agora é possível ler e gravar arquivos específicos do aplicativo em dispositivos de armazenamento externo secundário, como quando um dispositivo fornece armazenamento emulado e um cartão SD. O novo método getExternalFilesDirs() funciona da mesma forma que o método getExternalFilesDir(), mas retorna uma matriz de objetos File. Antes de ler ou gravar em qualquer um dos caminhos retornados por esse método, transmita o objeto File ao novo método getStorageState() para verificar se o armazenamento está disponível.

Outros métodos para acessar o diretório de cache específico do app e o diretório OBB agora também têm versões correspondentes que fornecem acesso a dispositivos de armazenamento secundário: getExternalCacheDirs() e getObbDirs(), respectivamente.

A primeira entrada na matriz File retornada é considerada o armazenamento externo principal do dispositivo, que é igual ao File retornado pelos métodos já existentes, como getExternalFilesDir().

Observação:a partir do Android 4.4, a plataforma não exige mais que seu app adquira WRITE_EXTERNAL_STORAGE ou READ_EXTERNAL_STORAGE quando você precisa acessar apenas as regiões específicas do app do armazenamento externo usando os métodos acima. No entanto, as permissões são necessárias se você quiser acessar as regiões compartilháveis do armazenamento externo, fornecidas por getExternalStoragePublicDirectory().

Adaptadores de sincronização

O novo método requestSync() em ContentResolver simplifica alguns dos procedimentos para definir uma solicitação de sincronização para seu ContentProvider, encapsulando solicitações no novo objeto SyncRequest, que você pode criar com SyncRequest.Builder. As propriedades em SyncRequest oferecem a mesma funcionalidade que as chamadas de sincronização ContentProvider existentes, mas adicionam a capacidade de especificar que uma sincronização será descartada se a rede for limitada, ativando a setDisallowMetered().

Entrada do usuário

Novos tipos de sensor

O novo sensor TYPE_GEOMAGNETIC_ROTATION_VECTOR fornece dados vetoriais de rotação com base em um magnetômetro, que é uma alternativa útil ao sensor TYPE_ROTATION_VECTOR quando um giroscópio não está disponível ou quando usado com eventos de sensor em lote para registrar a orientação do dispositivo enquanto o smartphone está em suspensão. Este sensor requer menos energia do que o TYPE_ROTATION_VECTOR, mas pode ser propenso a dados de eventos com ruído e é mais eficaz quando o usuário está ao ar livre.

Além disso, o Android agora tem compatibilidade com sensores de passo integrados no hardware:

TYPE_STEP_DETECTOR
Este sensor aciona um evento sempre que o usuário dá um passo. Em cada etapa do usuário, o sensor envia um evento com valor de 1,0 e um carimbo de data/hora que indica quando a etapa ocorreu.
TYPE_STEP_COUNTER
Esse sensor também aciona um evento em cada etapa detectada, mas informa o número total acumulado de passos desde que o sensor foi registrado por um app.

Esteja ciente de que esses dois sensores de passo nem sempre fornecem os mesmos resultados. Os eventos TYPE_STEP_COUNTER ocorrem com uma latência maior do que os de TYPE_STEP_DETECTOR, mas isso ocorre porque o algoritmo TYPE_STEP_COUNTER faz mais processamento para eliminar falsos positivos. A entrega de eventos do TYPE_STEP_COUNTER pode ser mais lenta, mas os resultados serão mais precisos.

Os dois sensores de etapa dependem do hardware (o Nexus 5 é o primeiro dispositivo compatível com eles), por isso verifique a disponibilidade com hasSystemFeature(), usando as constantes FEATURE_SENSOR_STEP_DETECTOR e FEATURE_SENSOR_STEP_COUNTER.

Eventos de sensor agrupados

Para gerenciar melhor a energia do dispositivo, as APIs SensorManager agora permitem especificar a frequência com que você quer que o sistema envie lotes de eventos de sensor para o app. Isso não reduz o número de eventos reais disponíveis para o app por um determinado período, mas reduz a frequência com que o sistema chama o SensorEventListener com atualizações do sensor. Ou seja, em vez de enviar cada evento ao aplicativo assim que ocorre, o sistema salva todos os eventos que ocorrem durante um intervalo de tempo e entrega todos juntos.

Para fornecer lotes, a classe SensorManager adiciona duas novas versões do método registerListener() que permitem especificar a "latência máxima do relatório". Esse novo parâmetro especifica o atraso máximo que seu SensorEventListener vai tolerar para a entrega de novos eventos do sensor. Por exemplo, se você especificar uma latência de um minuto em lote, o sistema vai entregar o conjunto recente de eventos agrupados em um intervalo de no máximo um minuto, fazendo chamadas consecutivas para o método onSensorChanged(), uma para cada evento em lote. Os eventos de sensor nunca excederão o valor da latência máxima de comunicação, mas podem chegar antes se outros aplicativos solicitarem uma latência menor para o mesmo sensor.

No entanto, esteja ciente de que o sensor entregará ao app os eventos em lote com base na latência de relatório somente enquanto a CPU estiver ativa. Embora o sensor de um equipamento compatível com agrupamento continue coletando eventos de sensor com o CPU suspenso, ele não ativará o CPU para enviar os eventos agrupados ao seu aplicativo. Quando, por acaso, o sensor ficar sem memória para eventos, ele começará a remover os eventos mais antigos para salvar os eventos mais novos. Para evitar a perda de eventos, ative o dispositivo antes que o sensor encha a memória e chame flush() para capturar o lote mais recente de eventos. Para estimar quando a memória vai ficar cheia e precisa ser limpa, chame getFifoMaxEventCount() para acessar o número máximo de eventos do sensor que ele pode salvar e divida esse número pela taxa em que o app quer cada evento. Use esse cálculo para definir alarmes de ativação com AlarmManager que invocam seu Service (que implementa o SensorEventListener) para limpar o sensor.

Observação:nem todos os dispositivos aceitam lotes de eventos de sensor porque isso exige suporte do sensor de hardware. No entanto, a partir do Android 4.4, use sempre os novos métodos registerListener(), porque, se o dispositivo não oferecer suporte a lotes, o sistema ignorará o argumento de latência em lote e enviará eventos de sensor em tempo real.

Identidade dos controladores

O Android agora identifica cada controle conectado com um número inteiro exclusivo que você pode consultar com getControllerNumber(), facilitando a associação de cada controle a um jogador diferente em um jogo. O número de cada controlador pode mudar devido à desconexão, conexão ou reconfiguração dos controladores pelo usuário. Portanto, registre uma instância de InputManager.InputDeviceListener para rastrear qual número corresponde a cada dispositivo de entrada. Em seguida, chame getControllerNumber() para cada InputDevice quando ocorrer uma mudança.

Os dispositivos conectados também agora fornecem IDs de produtos e fornecedores que estão disponíveis na getProductId() e na getVendorId(). Se você precisar modificar seus mapeamentos de teclas com base no conjunto de chaves disponível em um dispositivo, consulte o dispositivo para verificar se determinadas chaves estão disponíveis com hasKeys(int...).

Interface do usuário

Modo de tela cheia imersivo

Para fornecer ao app um layout que preencha toda a tela, a nova flag SYSTEM_UI_FLAG_IMMERSIVE para setSystemUiVisibility() (quando combinada com SYSTEM_UI_FLAG_HIDE_NAVIGATION) ativa um novo modo de tela cheia imersivo. Mesmo com o modo de tela cheia imersivo ativado, sua atividade continua recebendo todos os eventos de toque. O usuário pode revelar as barras do sistema com um movimento para dentro junto da região em que as barras do sistema normalmente aparecem. Isso limpa a flag SYSTEM_UI_FLAG_HIDE_NAVIGATION (e SYSTEM_UI_FLAG_FULLSCREEN, se aplicada) para que as barras do sistema permaneçam visíveis. No entanto, se você quiser que as barras do sistema fiquem ocultas novamente após alguns momentos, use a flag SYSTEM_UI_FLAG_IMMERSIVE_STICKY.

Barras do sistema translúcidas

Agora você pode deixar as barras do sistema parcialmente translúcidas com os novos temas, Theme.Holo.NoActionBar.TranslucentDecor e Theme.Holo.Light.NoActionBar.TranslucentDecor. Ao ativar as barras translúcidas, o layout vai preencher a área atrás das barras. Portanto, você também precisa ativar fitsSystemWindows para a parte do layout que não precisa ser coberta pelas barras.

Se você estiver criando um tema personalizado, defina um deles como o tema pai ou inclua as propriedades de estilo windowTranslucentNavigation e windowTranslucentStatus.

Ouvinte de notificação aprimorado

O Android 4.3 adicionou as APIs NotificationListenerService, permitindo que os aplicativos recebam informações sobre novas notificações à medida que são postadas pelo sistema. No Android 4.4, os listeners de notificação podem recuperar metadados adicionais para a notificação e completar detalhes sobre as ações da notificação:

O novo campo Notification.extras inclui um Bundle para enviar outros metadados ao criador de notificações, como EXTRA_TITLE e EXTRA_PICTURE. A nova classe Notification.Action define as características de uma ação anexada à notificação, que você pode recuperar no novo campo actions.

Espelhamento de desenháveis para layouts RTL

Nas versões anteriores do Android, se o app inclui imagens que precisam inverter a orientação horizontal para layouts da direita para a esquerda, é necessário incluir a imagem espelhada em um diretório de recursos drawables-ldrtl/. Agora, o sistema pode espelhar imagens automaticamente ativando o atributo autoMirrored em um recurso drawable ou chamando setAutoMirrored(). Quando ativada, a Drawable é espelhada automaticamente quando a direção do layout é da direita para a esquerda.

Acessibilidade

A classe View agora permite declarar "regiões ativas" para partes da interface que atualizam dinamicamente com novo conteúdo de texto, adicionando o novo atributo accessibilityLiveRegion ao layout XML ou chamando setAccessibilityLiveRegion(). Por exemplo, uma tela de login com um campo de texto que exibe uma notificação de "senha incorreta" precisa ser marcada como uma região ativa para que o leitor de tela reconheça a mensagem quando ela mudar.

Os apps que oferecem um serviço de acessibilidade agora também podem aprimorar os recursos com novas APIs que fornecem informações sobre coleções de visualizações, como visualizações de lista ou grade, usando AccessibilityNodeInfo.CollectionInfo e AccessibilityNodeInfo.CollectionItemInfo.

Permissões do app

Confira a seguir as novas permissões que o app precisa solicitar com a tag <uses-permission> para usar determinadas APIs:

INSTALL_SHORTCUT
Permite que um aplicativo instale um atalho na tela de início
UNINSTALL_SHORTCUT
Permite que um aplicativo desinstale um atalho na tela de início
TRANSMIT_IR
Permite que um aplicativo use o transmissor IR do dispositivo, se disponível.

Observação:a partir do Android 4.4, a plataforma não exige mais que seu app adquira WRITE_EXTERNAL_STORAGE ou READ_EXTERNAL_STORAGE quando você quiser acessar regiões específicas do armazenamento externo usando métodos como getExternalFilesDir(). No entanto, as permissões ainda serão necessárias se você quiser acessar as regiões compartilháveis do armazenamento externo, fornecidas por getExternalStoragePublicDirectory().

Recursos do dispositivo

Veja a seguir os novos recursos de dispositivo que você pode declarar com a tag <uses-feature> para declarar os requisitos do app e ativar o filtro no Google Play ou verificar no momento da execução:

FEATURE_CONSUMER_IR
O dispositivo é capaz de se comunicar com dispositivos de infravermelho do consumidor.
FEATURE_DEVICE_ADMIN
O dispositivo é compatível com a aplicação de políticas pelos administradores do dispositivo.
FEATURE_NFC_HOST_CARD_EMULATION
O dispositivo oferece suporte à emulação de cartão NFC com base em host.
FEATURE_SENSOR_STEP_COUNTER
O dispositivo inclui um hardware de contador de passos.
FEATURE_SENSOR_STEP_DETECTOR
O dispositivo inclui um hardware que detecta passos.

Para ter uma visão detalhada de todas as mudanças da API no Android 4.4, consulte o Relatório de diferenças da API.