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, você precisa fazer o download da imagem do sistema do Android 4.4 e da plataforma do SDK no SDK Manager o mais rápido possível. Se você não tiver um dispositivo com o Android 4.4 para testar seu app, use a imagem do sistema do Android 4.4 para testar o app no Android Emulator. Em seguida, crie seus apps com a plataforma Android 4.4 para começar a usar as APIs mais recentes.

Atualização do nível da API

Para otimizar melhor seu app para dispositivos com o Android 4.4, defina targetSdkVersion como "19", instale-o em uma imagem do sistema 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 compatibilidade com versões mais antigas adicionando condições ao seu código que conferem 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 Suporte a diferentes versões de plataforma.

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

Mudanças de comportamento importantes

Se você já publicou um app para Android anteriormente, saiba que ele pode ser afetado pelas mudanças do Android 4.4.

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

Seu app não pode ler arquivos compartilhados no armazenamento externo quando executado no Android 4.4, a menos que tenha a permissão READ_EXTERNAL_STORAGE. Ou seja, os arquivos dentro do diretório retornado por getExternalStoragePublicDirectory() não podem mais ser acessados sem a 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 do app para a versão "19" ou mais recente.

O código subjacente à classe WebView e às APIs relacionadas foi atualizado para ser baseado em um snapshot moderno do código-fonte do Chromium. Isso traz uma variedade de melhorias no desempenho, suporte a novos recursos HTML5 e suporte à depuração remota do seu conteúdo WebView. O escopo desse upgrade significa que, se o app usar WebView, o comportamento dele poderá ser afetado em alguns casos. Embora as mudanças de comportamento conhecidas sejam documentadas e afetem o app principalmente quando você atualiza a targetSdkVersion para "19" ou mais recente, o novo WebView opera no "modo quirks" para oferecer 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.

Por isso, se o app usa WebView, é importante testar no Android 4.4 o quanto antes 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 "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 um horário exato do relógio, mas ainda for importante que ele seja invocado durante um período específico (como entre 14h e 16h), você pode usar o novo método setWindow(), que aceita um horário "mais cedo" para o alarme e um "intervalo" após o 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 (como 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ê tiver definido a targetSdkVersion como "18" ou uma versão anterior, seus alarmes continuarão a se comportar da mesma forma que nas versões anteriores 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 suas operações de sincronização dentro de 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ê tiver definido a 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 IU 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 para impressão em uma ParcelFileDescriptor.

Para gravar seu conteúdo no ParcelFileDescriptor, você precisa 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 o 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 criando uma subclasse da 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 app, consulte 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 "app de SMS padrão". Depois de selecionado, somente o app de SMS padrão poderá gravar no provedor de SMS, e somente 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 não selecionados como padrão de SMS só podem ler o provedor de SMS, mas também podem ser notificados quando um novo SMS chega ao ouvir 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.

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 seu app, crie um componente de serviço com base na classe HostApduService. Se, em vez disso, o app usar um elemento de segurança para a emulação de cartão, será necessário criar um serviço baseado na classe OffHostApduService, que não estará diretamente envolvida nas transações, mas é necessário para registrar os AIDs que precisam ser processados pelo elemento de segurança.

Para ver 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 de leitura 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 terminal de pagamento (um dispositivo 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. Em seguida, você pode consultar as frequências de infravermelho 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 somente com dispositivos que tenham um, inclua um elemento <uses-feature> no manifesto para "android.hardware.consumerir" (FEATURE_CONSUMER_IR).

Multimídia

Reprodução adaptativa

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

Você pode ativar a reprodução adaptável adicionando duas chaves a MediaFormat que especificam a resolução máxima que o app exige 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 é compatível com esse recurso chamando isFeatureSupported(String) com FEATURE_AdaptivePlayback.

Observação:o suporte à reprodução adaptativa é específico ao 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 receber 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 nas unidades de frames, além do tempo estimado em que esse frame foi apresentado ou está confirmado para ser apresentado.

Você pode usar o valor de nanoTime em AudioTimestamp (que é monotônico) para encontrar o frame de vídeo associado mais próximo em comparação com framePosition para que seja possível soltar, duplicar ou interpolar frames de vídeo para corresponder ao áudio. Também é 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 à medida que 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 da imagem com um produtor, como MediaPlayer ou MediaCodec. Para receber notificações quando novas imagens estiverem disponíveis na superfície, implemente a interface ImageReader.OnImageAvailableListener e registre-a com setOnImageAvailableListener().

Agora, à medida que você desenha conteúdo para o Surface, o ImageReader.OnImageAvailableListener recebe uma chamada para onImageAvailable() conforme cada novo frame de imagem fica disponível, 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, formato, dimensões e dados de pixels 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 valores medidos mais recentes.

Atenuador de ruído

A LoudnessEnhancer é uma nova subclasse do AudioEffect que permite aumentar o volume audível do MediaPlayer ou 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 outras mídias estão sendo reproduzidas.

Controladores remotos

O Android 4.0 (nível 14 da API) introduziu as APIs RemoteControlClient, que permitem que os apps de mídia consumam eventos do controlador 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 controlador remoto, implemente a interface do usuário da forma que você quiser. No entanto, para fornecer os eventos do botão de mídia ao app de música do usuário, é necessário criar um serviço que estenda a classe NotificationListenerService e implemente a interface RemoteController.OnClientUpdateListener. Usar o NotificationListenerService como base é importante 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 precisam ser implementados, mas se você estiver preocupado apenas com os eventos dos controles de mídia para processar a reprodução de mídia, deixe a implementação deles vazia 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 pelo controle remoto.

A nova classe Rating encapsula informações sobre a avaliação de um usuário. Uma classificação é definida pelo estilo dela (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 pelo controle remoto, implemente a nova interface RemoteControlClient.OnMetadataUpdateListener e transmita uma instância para setMetadataUpdateListener(). Quando o usuário mudar a nota, seu RemoteControlClient.OnMetadataUpdateListener vai receber 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 durante a reprodução de vídeos do HTTP Live Stream (HLS), exibindo a faixa de legenda de acordo com as preferências de legenda definidas pelo usuário nas configurações do sistema.

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

Se você não usar VideoView para exibir seu conteúdo de vídeo, a sobreposição de legenda precisa corresponder 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 de iniciar o vídeo, detecte as mudanças nas preferências 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 IU, 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 a ViewGroup que contém os componentes de IU 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.

Você pode 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 TransitionManager para realizar as etapas 3 e 4. Uma delas é transmitir o Scene para o método estático go(). Isso encontra a visualização mãe da cena no layout atual e executa 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 devem ocorrer entre cenas predefinidas, usando um arquivo XML no diretório res/transition/ do projeto. Dentro de um elemento <transitionManager>, especifique uma ou mais tags <transition>, cada uma especificando 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 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 mudanças de propriedade e criar as animações que você quiser com base nelas. Por exemplo, é possível fornecer uma subclasse de Transition que detecta mudanças na propriedade "rotação" de uma visualização e, em seguida, animar as mudanças.

Para mais informações, consulte a documentação 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 criar uma subclasse para 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 alocados 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 do bitmap subjacente O método reconfigure() também oferece uma maneira conveniente de combinar essas mudanças com uma chamada.

No entanto, você não deve reconfigurar um bitmap que está em uso no sistema de visualização, porque o buffer de pixel subjacente não será remapeado de maneira previsível.

Conteúdo do usuário

Estrutura de acesso ao armazenamento

Nas versões anteriores do Android, se você quiser que o 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 seu 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 para gravação) sem importar o arquivo para o app.

Se você estiver desenvolvendo um app que oferece serviços de armazenamento de arquivos, como um serviço de salvamento na nuvem, poderá usar essa IU unificada para selecionar 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 retorna um Cursor que descreve todos os arquivos no diretório especificado, usando colunas definidas em DocumentsContract.Document.
queryDocument()
Isso precisa retornar um Cursor que descreve o arquivo especificado, usando colunas definidas em DocumentsContract.Document.
openDocument()
Isso retorna um ParcelFileDescriptor que representa o arquivo especificado. O sistema chama esse método quando o usuário seleciona um arquivo e o app cliente solicita acesso chamando openFileDescriptor().

Para mais informações, consulte o guia Estrutura 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 os diretórios de cache específico do app e OBB agora 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 é o mesmo que o File retornado por métodos existentes, como getExternalFilesDir().

Observação:no Android 4.4 e versões mais recentes, a plataforma não exige mais que seu app adquira WRITE_EXTERNAL_STORAGE ou READ_EXTERNAL_STORAGE quando você precisar acessar apenas 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 pelo 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 a ContentProvider, encapsulando as solicitações no novo objeto SyncRequest, que pode ser criado 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 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, o 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. Esse sensor consome menos energia do que o TYPE_ROTATION_VECTOR, mas pode estar propenso a dados de eventos com ruído e é mais eficaz quando o usuário está em ambientes externos.

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. A cada etapa do usuário, o sensor envia um evento com valor de 1,0 e um carimbo de data/hora indicando quando a etapa ocorreu.
TYPE_STEP_COUNTER
Esse sensor também aciona um evento em cada etapa detectada, mas fornece o número total acumulado de passos desde que o sensor foi registrado pela primeira vez por um app.

Lembre-se de que esses dois sensores de passo nem sempre geram 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. Portanto, o TYPE_STEP_COUNTER pode ser mais lento para fornecer eventos, mas os resultados dele devem ser mais precisos.

Os dois sensores de passo dependem do hardware (o Nexus 5 é o primeiro dispositivo a oferecer suporte a eles), portanto, 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 sim 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 oferecer lotes, a classe SensorManager adiciona duas novas versões do método registerListener(), que permitem especificar a "latência máxima de relatórios". Esse novo parâmetro especifica o atraso máximo que seu SensorEventListener vai tolerar para enviar 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 em lote em um intervalo de até um minuto, fazendo chamadas consecutivas para o método onSensorChanged(), uma para cada evento reunido 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, lembre-se de que o sensor vai enviar 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 de eventos mais recente. Para estimar quando a memória vai ficar cheia e precisa ser limpa, chame getFifoMaxEventCount() para descobrir o número máximo de eventos do sensor que ele pode salvar e divida esse número pela taxa que o app quer cada evento. Use esse cálculo para definir alarmes de ativação com AlarmManager que invocam o Service (que implementa o SensorEventListener) para limpar o sensor.

Observação:nem todos os dispositivos são compatíveis com o agrupamento de eventos de sensor porque isso exige a ajuda do sensor de hardware. No entanto, a partir do Android 4.4, use sempre os novos métodos registerListener(). Se o dispositivo não oferecer suporte ao agrupamento em lote, 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 se os controladores forem desconectados, conectados ou reconfigurados pelo usuário. Portanto, registre uma instância de InputManager.InputDeviceListener para rastrear qual número de controlador 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 produto e fornecedor que estão disponíveis no getProductId() e no getVendorId(). Se você precisar modificar seus mapeamentos de teclas com base no conjunto de chaves disponível em um dispositivo, faça uma consulta 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 sinalização 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 sinalização SYSTEM_UI_FLAG_HIDE_NAVIGATION (e a sinalização 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 depois de alguns instantes, 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 vai 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 nele.

Ouvinte de notificação aprimorado

O Android 4.3 adicionou as APIs NotificationListenerService, permitindo que os apps 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 detalhes completos sobre as ações da notificação:

O novo campo Notification.extras inclui um Bundle para enviar outros metadados ao builder 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 incluir imagens que precisem inverter a orientação horizontal para layouts da direita para a esquerda, você precisará incluir a imagem espelhada em um diretório de recursos drawables-ldrtl/. Agora, o sistema pode espelhar imagens automaticamente para você 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 IU que são atualizadas 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 leia a mensagem quando ela mudar.

Apps que fornecem um serviço de acessibilidade agora também podem melhorar os recursos com as 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 pelo getExternalStoragePublicDirectory().

Recursos do dispositivo

Veja a seguir os novos recursos de dispositivos que você pode declarar com a tag <uses-feature> para declarar os requisitos do app e ativar a filtragem no Google Play ou a verificação 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 da política do dispositivo pelos administradores.
FEATURE_NFC_HOST_CARD_EMULATION
O dispositivo oferece suporte à emulação de cartão NFC baseado em host.
FEATURE_SENSOR_STEP_COUNTER
O dispositivo inclui um hardware de contador de passos.
FEATURE_SENSOR_STEP_DETECTOR
O dispositivo inclui um detector de passos de hardware.

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