Android 4.4 APIs

Nível da API: 19

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

Como desenvolvedor de aplicativos, você deve baixar a imagem do sistema do Android 4.4 e a plataforma do SDK pelo SDK Manager assim que possível. Se seu dispositivo não possui o Android 4.4 para você testar o aplicativo, use a imagem do sistema do Android 4.4 para testá-lo no emulador de Android. Depois, compile-o na plataforma do Android 4.4 para começar a usar as APIs mais recentes.

Atualização do nível da API

Para otimizar ainda mais o aplicativo para dispositivos com Android 4.4, você deve definir targetSdkVersion como "19", instalá-la em uma imagem do sistema do Android 4.4, testá-la e depois publicar uma atualização com essa mudança.

Você pode usar as APIs do Android 4.4 e ainda oferecer compatibilidade com versões anteriores adicionando ao código condições que verifiquem o nível da API do sistema antes de executar APIs não compatíveis com sua minSdkVersion. Para saber mais sobre manutenção de retrocompatibilidade, leia Compatibilidade com diferentes versões de plataforma.

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

Mudanças de comportamento importantes

Se você já publicou um aplicativo 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 aplicativo não consegue ler arquivos compartilhados em armazenamento externo quando executado no Android 4.4, a menos que tenha a permissão READ_EXTERNAL_STORAGE. Ou seja, os arquivos dentro da pasta retornados por getExternalStoragePublicDirectory() não são mais acessíveis sem a permissão. No entanto, se você precisar acessar somente as pastas específicas do aplicativo, fornecidas por getExternalFilesDir(), não precisa da permissão READ_EXTERNAL_STORAGE.

Se seu aplicativo usa o WebView...

Seu aplicativo pode se comportar de forma diferente quando executado no Android 4.4, principalmente ao atualizar a targetSdkVersion do aplicativo para "19" ou posterior.

O código referente à classe WebView e a APIs relacionadas foi atualizado para se basear em um compacto moderno do código-fonte do Chromium. Isso possibilita diversas melhorias no desempenho, compatibilidade com novos recursos HTML5 e com depuração remova do conteúdo do WebView. O escopo dessa atualização diz que, se seu aplicativo usa o WebView, seu comportamento pode ser impactado em alguns casos. Embora mudanças de comportamento conhecidas sejam documentadas e afetem o aplicativo principalmente depois de atualizar a targetSdkVersion do aplicativo para "19" ou posterior — o novo WebView opera em "modo evasivo" para fornecer algumas funções de legado para aplicativos direcionados a APIs de nível 18 ou anteriores — é possível que o aplicativo dependa de comportamentos desconhecidos da versão anterior do WebView.

Sendo assim, se seu aplicativo usa o WebView, é importante testá-lo no Android 4.4 o quanto antes e consultar Como migrar para o WebView do Android 4.4 para entender como seu aplicativo pode ser afetado depois da atualização da targetSdkVersion para "19" ou posterior.

Se seu aplicativo usa o AlarmManager...

Ao configurar a targetSdkVersion do aplicativo para "19" ou posterior, os alarmes que você cria usando set() ou setRepeating() ficarão inexatos.

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 seu alarme não está associado a um horário exato do relógio, mas ainda é importante que ele seja invocado dentro de um intervalo de tempo específico (como de 14h às 16h), você pode usar o novo método setWindow(), que aceita um horário "mais adiantado" para o alarme e uma "janela" de tempo após o horário mais adiantado dentro da qual o sistema deve invocar o alarme.

Se seu alarme deve ser programado em uma hora exata do relógio (como em um lembrete de evento de calendário), você pode usar o novo método setExact().

Esse comportamento de agrupamento inexato aplica-se somente a aplicativos atualizados. Se você definir a targetSdkVersion como "18" ou anterior, os alarmes continuarão se comportando como o faziam em versões anteriores quando executados no Android 4.4.

Se seu aplicativo sincroniza dados usando o ContentResolver...

Ao definir a targetSdkVersion do seu aplicativo como "19" ou posterior, criar uma sincronização com addPeriodicSync() realizará as operações de sincronização dentro de um intervalo flexível padrão de aproximadamente 4% do período que você especificar. 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, você deve começar a usar o novo método requestSync(). Para obter mais detalhes, veja a seção abaixo sobre Adaptadores de sincronização.

Esse comportamento de intervalo flexível aplica-se somente a aplicativos atualizados. Se você definir a targetSdkVersion como "18" ou anterior, suas solicitações de sincronização existentes continuarão se comportando como o faziam em versões anteriores quando 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. A estrutura android.print fornece todas as APIs necessárias para especificar um documento a imprimir e fornecê-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 quiser imprimir conteúdo da IU como um documento, antes você precisa criar uma subclasse de PrintDocumentAdapter. Dentro dessa classe, você deve implementar alguns métodos de retorno de chamada, incluindo onLayout(), para definir seu layout com base nas propriedades de impressão fornecidas, e onWrite() para serializar seu conteúdo imprimível em um ParcelFileDescriptor.

Para gravar o conteúdo no ParcelFileDescriptor, você deve passar um PDF a ele. As novas PdfDocument APIs oferecem um modo conveniente de fazer isso ao fornecer um Canvas por getCanvas(), em que você pode desenhar seu conteúdo imprimível. 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 de acordo com a solicitação do usuário usando o método PrintManager, print(), que assume o PrintDocumentAdapter como um de seus 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 instância de PrintHelper, definir o modo de escala com setScaleMode() e passar o Bitmap a 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 uma impressora original de fábrica, você pode usar a estrutura android.printservice para criar interoperabilidade entre suas impressoras e dispositivos Android. É possível criar e distribuir serviços de impressão como APKs, que os usuários podem instalar nos dispositivos. Um aplicativo de serviço de impressão opera, principalmente, como um serviço sem periféricos ao tornar a classe PrintService uma subclasse, que recebe trabalhos de impressão do sistema e comunica os trabalhos às impressoras usando os protocolos adequados.

Para saber mais sobre como imprimir o conteúdo do seu aplicativo, leia Impressão de conteúdo.

Provedor de SMS

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

Começando com o 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 aplicativo SMS padrão pode gravar no Provedor de SMS e recebe a transmissão de SMS_DELIVER_ACTION quando o usuário recebe um SMS, ou de WAP_PUSH_DELIVER_ACTION quando recebe um MSS. O aplicativo de SMS padrão é responsável por gravar detalhes no Provedor de SMS quando ele recebe ou envia uma nova mensagem.

Outros aplicativos não selecionados como o aplicativo de SMS padrão só podem ler o Provedor de SMS, mas também podem receber notificação quando um SMS é recebido por meio da transmissão de SMS_RECEIVED_ACTION, que é uma transmissão não abortável que pode ser fornecida a diversos aplicativos. 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 obter mais informações, leia a publicação Preparação dos aplicativos SMS para o KitKat do blogue.

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 aplicativo, crie um componente de serviço com base na classe HostApduService. Enquanto que, se seu aplicativo usa um elemento protegido para a emulação de cartão, você precisa criar um serviço com base na classe OffHostApduService que não se envolverá diretamente nas transações, mas que é necessário para registrar os AIDs que devem ser tratados pelo elemento protegido.

Para saber mais, 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 leitor para a atividade com enableReaderMode(), fornecendo uma implementação de NfcAdapter.ReaderCallback que receba um retorno de chamada ao se detectar novas tags.

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

Transmissores infravermelhos

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

Antes, você sempre deve verificar se um dispositivo inclui um transmissor IR chamando hasIrEmitter() mas, se seu aplicativo só for compatível com dispositivos que só têm um, você deve incluir um elemento <uses-feature> no manifesto para "android.hardware.consumerir" (FEATURE_CONSUMER_IR).

Multimídia

Reprodução adaptativa

Agora há compatibilidade com reprodução de vídeo adaptativa com as MediaCodec APIs, permitindo mudança suave na resolução durante a reprodução em uma Surface— você pode alimentar os quadros de entrada do decodificador de uma nova resolução para mudar a resolução dos buffers de saída sem um hiato significativo.

É possível ativar a reprodução adaptativa adicionando duas chaves a MediaFormat que especifiquem a resolução máxima que seu aplicativo exige do codec: KEY_MAX_WIDTH e KEY_MAX_HEIGHT. Depois de adicioná-las a MediaFormat, passe MediaFormat à instância 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, é preciso verificar se o dispositivo é compatível com reprodução adaptativa chamando isFeatureSupported(String) com FEATURE_AdaptivePlayback.

Observação: A compatibilidade com reprodução adaptativa é específica 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 de tempo sobre um "quadro" específico em uma transmissão de áudio tratado por AudioTrack. Para obter a marcação de data e hora mais recente, instancie um objeto AudioTimestamp e passe-o para getTimestamp(). Se a solicitação de marcação de data e hora der certo, a instância AudioTrack será preenchida com uma posição em unidades de quadro, além de um tempo estimado de quando esse quadro foi apresentado ou deve ser apresentado.

Você pode usar o valor de nanoTime em AudioTimestamp (que é monotônico) para encontrar o quadro associado mais próximo do vídeo em relação a framePosition para poder inserir, duplicar ou interpolar quadros de vídeo e alinhar com o áudio. Como alternativa, é possível determinar o tempo delta entre o valor de nanoTime e o tempo esperado de um futuro quadro do vídeo (levando-se em conta a taxa de amostragem) para prever que quadro de áudio é esperado para o mesmo momento que o quadro de vídeo.

Leitor de imagens de superfície

A nova ImageReader API fornece a você acesso direto a buffers de imagem à medida que são renderizados em uma Surface. Você pode adquirir um ImageReader com o método estático newInstance(). Depois, chame getSurface() para criar uma nova Surface e forneça os dados da imagem com um reprodutor, como o MediaPlayer ou o MediaCodec. Para receber notificação quando novas imagens forem disponibilizadas na superfície, implemente a interface ImageReader.OnImageAvailableListener e registre-a com setOnImageAvailableListener().

Agora que você inseriu conteúdo na Surface, seu ImageReader.OnImageAvailableListener receberá uma chamada de onImageAvailable() para cada novo quadro de imagem disponibilizado, fornecendo a você o ImageReader correspondente. É possível usar o ImageReader para adquirir os dados de imagem do quadro como um objeto Image chamando acquireLatestImage() ou acquireNextImage().

O objeto Image fornece acesso direto à data e 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 devem ser formatadas de acordo com um dos tipos definidos por constantes em ImageFormat ou PixelFormat.

Medição de pico e RMS

Agora, você pode consultar o pico e o RMS da transmissão de áudio ativa em Visualizer criando uma nova instância de Visualizer.MeasurementPeakRms e passando-a para getMeasurementPeakRms(). Ao chamar esse método, os valores de pico e RMS da Visualizer.MeasurementPeakRms em questão são definidos como os últimos valores medidos.

Atenuador de ruído

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

Controladores remotos

O Android 4.0 (API de nível 14) introduziu as APIs RemoteControlClient, que permitem que aplicativos de mídia consumam eventos de controlador de mídia de clientes remotos, como controles de mídia na tela bloqueada. Agora, as novas RemoteController APIs permitem compilar seu próprio controlador remoto, possibilitando a criação de novos aplicativos e periféricos inovadores para controlar a reprodução de qualquer aplicativo de mídia integrado a RemoteControlClient.

Para criar um controlador remoto, você pode implementar a interface do usuário da forma que quiser, mas, para fornecer os eventos de botão de mídia ao aplicativo de mídia do usuário, você deve criar um serviço que estenda a classe NotificationListenerService e implemente a interface RemoteController.OnClientUpdateListener. Usando o NotificationListenerService como a base é importante, porque ele fornece as restrições de privacidade necessárias, que exigem que os usuários configurem seu aplicativo como um ouvinte de notificação dentro das configurações de segurança do sistema.

A classe NotificationListenerService inclui dois métodos abstratos que você deve implementar, mas se somente os eventos de controlador de mídia para manipulação de reprodução de mídia preocupam você, deixe a implementação deles vazia e concentre-se nos métodos RemoteController.OnClientUpdateListener.

Classificação de controladores remotos

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

A nova classe Rating encapsula as informações da classificação de um usuário. Uma classificação é definida pelo seu estilo (RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS, RATING_5_STARS ou RATING_PERCENTAGE) e o valor adequado para esse estilo.

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

Para receber um retorno de chamada quando um usuário alterar a classificação pelo controlador remoto, implemente a nova interface RemoteControlClient.OnMetadataUpdateListener e passe uma instância para setMetadataUpdateListener(). Quando o usuário alterar a classificação, seu RemoteControlClient.OnMetadataUpdateListener receberá uma chamada de onMetadataUpdate(), passando RATING_KEY_BY_USER como a chave e um objeto Rating como o valor.

Legendas

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

Além disso, você pode fornecer VideoView com as trilhas 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 no vídeo de acordo com as preferências do usuário.

Se você não usa VideoView para exibir seu conteúdo de vídeo, você deve compatibilizar a sobreposição da legenda com as preferências de legenda do usuário o máximo possível. Uma nova CaptioningManager API permite consultar as preferências de legenda do usuário, incluindo estilos definidos por CaptioningManager.CaptionStyle, como tipo de letra e cor. Caso o usuário ajuste algumas preferências depois de o vídeo já ter iniciado, você deve detectar mudanças às preferências registrando uma instância de CaptioningManager.CaptioningChangeListener para receber um retorno de chamada quando alguma das preferências mudar, em seguida atualizar as legendas conforme a necessidade.

Animação e gráficos

Cenas e transições

A nova estrutura android.transition fornece APIs que facilitam animações em diferentes estados da sua interface do usuário. Um recurso muito importante é a capacidade de definir estados distintos para a 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 o ViewGroup contendo os componentes de IU que você deseja alterar.
  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. Scene contém metadados que descrevem as propriedades de um layout que são necessárias para realizar uma transição, incluindo o layout e a visualização parente da cena. É possível criar uma Scene usando um construtor de classe ou o método estático getSceneForLayout().

Em seguida, você precisa usar o TransitionManager para realizar as etapas 3 e 4. Uma forma é passar a Scene ao método estático go(). Isso serve para encontrar a visualização parente da cena no layout atual e realizar uma transição nas visualizações secundárias para se obter o layout definido pela Scene.

Como alternativa, você não precisa criar um objeto Scene, mas pode chamar beginDelayedTransition(), especificando um ViewGroup que contenha as visualizações que deseja 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 controle adicional, você pode definir conjuntos de transições que devem ocorrer entre cenas pré-definidas, usando um arquivo XML na pasta res/transition/ do seu projeto. Dentro de um elemento <transitionManager>, especifique uma ou mais tags <transition>, com cada uma especificando uma cena (referência a um arquivo de layout), e a transição a ser aplicada ao entrar e/ou sair da cena. Em seguida, infle esse conjunto de transições usando inflateTransitionManager(). Use o TransitionManager retornado para executar cada transição com transitionTo(), passando uma Scene que seja representada por uma das tags <transition>. Além disso, você pode definir conjuntos de transições programaticamente com as TransitionManager APIs.

Ao especificar uma transição, você pode usar diversos tipos predefinidos estabelecidos por subclasses de Transition, como Fade e ChangeBounds. Se você não especificar um tipo de transição, o sistema usa AutoTransition por padrão, que esmaece, move e redimensiona visualizações automaticamente conforme a necessidade. Além disso, você pode criar transições personalizadas estendendo uma dessas classes para realizar as animações da forma que você preferir. Uma transição personalizada pode acompanhar as mudanças de propriedade e criar a animação que você quiser com base nessas mudanças. 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 obter mais informações, veja 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 acompanhar o estado de uma animação, você pode implementar a interface Animator.AnimatorPauseListener, que fornece retornos de chamada quando uma animação é pausada e retomada: pause() e resume(). Em seguida, adicione um ouvinte a um objeto Animator com addPauseListener().

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

Bitmaps reutilizáveis

Agora você pode reutilizar qualquer bitmap mutável em BitmapFactory para decodificar outro bitmap — mesmo se o novo bitmap tiver tamanho diferente — desde que a contagem de bytes resultante do bitmap decodificado (disponibilizada por getByteCount()) seja menor ou igual à contagem de bytes alocada do bitmap reutilizado (disponibilizada por getAllocationByteCount()). Para saber mais, consulte inBitmap.

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

No entanto, você não deve reconfigurar um bitmap que esteja em uso no sistema de visualizações, porque o buffer de pixel em questão não será mapeado novamente de forma previsível.

Conteúdo ao usuário

Estrutura de acesso ao armazenamento

Em versões anteriores do Android, se você quiser que o aplicativo recupere um tipo específico de arquivo em outro aplicativo, ele deve invocar uma intent com a ação ACTION_GET_CONTENT. Essa ação ainda é o modo adequado de solicitar um arquivo que você queira importar para o aplicativo. No entanto, o Android 4.4 introduziu a ação ACTION_OPEN_DOCUMENT, que permite que o usuário seleciona um arquivo de um tipo específico e conceda ao aplicativo acesso de leitura de longo prazo a esse arquivo (possivelmente com acesso de gravação), sem importar o arquivo para o aplicativo.

Se estiver desenvolvendo um aplicativo que fornece serviços de armazenamento de arquivos (como serviço de armazenamento em nuvem), você pode participar dessa IU unificada para coleta de arquivos implementando um provedor de conteúdo como uma subclasse da nova classe DocumentsProvider. Sua subclasse de DocumentsProvider deve incluir um filtro de intent que aceite a ação PROVIDER_INTERFACE ("android.content.action.DOCUMENTS_PROVIDER"). Depois, implemente os quatro métodos abstratos no DocumentsProvider:

queryRoots()
Isso retornará um Cursor que descreve as pastas-raiz do armazenamento do documento, usando colunas definidas em DocumentsContract.Root.
queryChildDocuments()
Isso retornará um Cursor que descreve todos os arquivos de determinada pasta, usando colunas definidas em DocumentsContract.Document.
queryDocument()
Isso retornará um Cursor que descreve o arquivo especificado, usando colunas definidas em DocumentsContract.Document.
openDocument()
Isso retornará um ParcelFileDescriptor que representa o arquivo especificado. O sistema chamará esse método quando o usuário selecionar um arquivo e o aplicativo cliente solicitar acesso a ele chamando openFileDescriptor().

Para obtermais 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() existente, mas ele retorna uma matriz de objetos File. Antes de ler ou gravar em algum dos caminhos retornados por esse método, passe o objeto File ao novo método getStorageState() para verificar se o armazenamento está disponível.

Outros métodos para acessar pasta de cache e de OBB específicas do aplicativo agora tem 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 principal armazenamento externo do dispositivo, que é igual à File retornada por métodos existentes, como getExternalFilesDir().

Observação: Começando com o Android 4.4, a plataforma não exige mais que o aplicativo adquira o WRITE_EXTERNAL_STORAGE ou READ_EXTERNAL_STORAGE quando você precisar acessar apenas regiões específicas do aplicativo 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 o ContentProvider por meio do encapsulamento de solicitações no novo objeto SyncRequest, que pode ser criado com SyncRequest.Builder. As propriedades da SyncRequest fornecem a mesma funcionalidade que as chamadas de sincronização existentes do ContentProvider, mas adiciona a capacidade de especificar que a sincronização deve ser removida se a rede for medida ativando setDisallowMetered().

Entrada do usuário

Novos tipos de sensor

O novo sensor TYPE_GEOMAGNETIC_ROTATION_VECTOR fornece dados de vetor de rotação com base em um magnetômetro, o que é uma alternativa muito útil ao sensor TYPE_ROTATION_VECTOR quando o giroscópio não estiver disponível ou for usado com eventos de sensor agrupados para registrar a orientação do dispositivo com o telefone em estado de suspensão. Esse sensor exige menos energia do que o TYPE_ROTATION_VECTOR, mas pode ser propenso a dados de evento com ruído e é mais eficaz quando o usuário está em ambientes 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. Após cada passo do usuário, o sensor fornece um evento com valor de 1.0 e uma marcação de data e hora indicando quando o evento ocorreu.
TYPE_STEP_COUNTER
Este sensor também aciona um evento após cada passo detectado, mas na verdade fornece o total acumulado de passos desde o momento em que este sensor foi registrado por um aplicativo.

Não se esqueça de que esses dois sensores de passo nem sempre geram os mesmos resultados. Os eventos de TYPE_STEP_COUNTER ocorrem com uma latência maior do que os de TYPE_STEP_DETECTOR, isso porque o algoritmo de TYPE_STEP_COUNTER realiza mais processamento para eliminar falsos positivos. Por isso, o TYPE_STEP_COUNTER pode ser mais lento para fornecer eventos, mas seus resultados devem ser mais precisos.

Ambos os sensores de passo são equipamentos dependentes (o Nexus 5 foi o primeiro dispositivo a oferecer compatibilidade com eles), por isso você deve checar 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 SensorManager APIs agora permitem especificar a frequência com que você quer que o sistema envie lotes de eventos de sensor ao aplicativo. Isso não reduz a quantidade real de eventos de sensor disponíveis para seu aplicativo por dado período, mas sim 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 ativar o agrupamento, a classe SensorManager adicione duas novas versões do método registerListener(), que permitem especificar a "latência máxima de comunicação". Esse novo parâmetro especifica o tempo máximo que seu SensorEventListener tolerará para enviar os novos eventos de sensor. Por exemplo, se você especificar uma latência de um minuto para o lote, o sistema enviará o conjunto recente de eventos agrupados em um intervalo não superior a um minuto, fazendo chamadas consecutivas do método onSensorChanged() — uma para cada evento agrupado. 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 enviará os eventos agrupados ao aplicativo com base na sua latência de comunicação somente enquanto o CPU estiver ativo. 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. Você pode evitar perder eventos ativando o dispositivo antes de o sensor preencher toda a memória e, depois, chamar flush() para capturar o lote de eventos mais recente. Para estimar quando a memória ficará cheia e precisará ser desocupada, chame getFifoMaxEventCount() para saber o numero máximo de eventos de sensor que ele pode salvar e divida esse número pela taxa à que seu aplicativo precisa de cada evento. Use esse cálculo para definir alarmes de ativação com AlarmManager que invoquem seu Service (que implementa o SensorEventListener) para esvaziar o sensor.

Observação: Nem todos os dispositivos são compatíveis com o agrupamento de eventos de sensor, porque a compatibilidade do sensor do aparelho é necessária. No entanto, a partir do Android 4.4, você sempre deve usar os novos métodos registerListener() porque, se o dispositivo não oferecer compatibilidade com o agrupamento, o sistema simplesmente ignorará o argumento de latência de lote e enviará eventos de sensor em tempo real.

Identidade dos controladores

Agora o Android identifica cada controlador conectado com um número inteiro exclusivo, que você pode consultar com getControllerNumber(), facilitando a associação de cada controlador a um jogador diferente em um jogo. O número atribuído a cada controlador pode mudar devido a desconexão, conexão ou reconfiguração dos controladores pelo usuário, então, você deve controlar que número de controlador corresponde a cada dispositivo de entrada registrando uma instância de InputManager.InputDeviceListener. Depois, chame getControllerNumber() para cada InputDevice ao ocorrer uma mudança.

Além disso, os dispositivos conectados também fornecem IDs de produto e fornecedor, que são disponibilizados por getProductId() e getVendorId(). Se precisar modificar seus mapeamentos de chave de acordo com o conjunto de chaves disponível em um dispositivo, você pode consultar o dispositivo com hasKeys(int...) para verificar se determinadas chaves estão disponíveis.

Interface do usuário

Modo de tela cheia imersivo

Para fornecer ao aplicativo um layout que preencha toda a tela, o novo sinalizador SYSTEM_UI_FLAG_IMMERSIVE para setSystemUiVisibility() (quando combinado com SYSTEM_UI_FLAG_HIDE_NAVIGATION) cria 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 apaga o sinalizador SYSTEM_UI_FLAG_HIDE_NAVIGATION (e o sinalizador SYSTEM_UI_FLAG_FULLSCREEN, se aplicável) para que as barras do sistema permaneçam visíveis. Mas, se você quiser que as barras do sistema fiquem ocultas de novo depois de alguns momentos, use o sinalizador 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 aplicar barras translúcidas, seu layout preencherá a área atrás das barras, por isso você também precisa ativar fitsSystemWindows para a parte do layout que não deve ser coberta pelas barras do sistema.

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

Ouvinte de notificação aprimorado

O Android 4.3 adicionou as APIs NotificationListenerService, que permitem que os aplicativos recebam informações sobre novas notificações à medida que são publicadas pelo sistema. No Android 4.4, os ouvintes 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 fornecer metadados adicionais, como EXTRA_TITLE e EXTRA_PICTURE, ao construtor de notificação. A nova classe Notification.Action define as características de uma ação vinculada à notificação, que você pode recuperar pelo novo campo actions.

Espelhamento de desenháveis para layouts RTL

Em versões anteriores do Android, se seu aplicativo continha imagens que deveriam ser invertidas da orientação horizontal para layouts "da direita para a esquerda", você deveria incluir a imagem espelhada em uma pasta de recursos de drawables-ldrtl/. Agora, o sistema pode espelhar as imagens automaticamente para você ativando o atributo autoMirrored em um recurso de desenhável ou chamando setAutoMirrored(). Quando ativado o Drawable é espelhado 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 atualizam-se dinamicamente com novo conteúdo de texto, por meio da adição do novo atributo accessibilityLiveRegion ao layout XML ou chamando setAccessibilityLiveRegion(). Por exemplo, uma tela de acesso com um campo de texto que exibe uma notificação de "senha incorreta" deve ser marcada como uma região ativa para que o leitor da tela declare a mensagem quando a região mudar.

Os aplicativos que fornecem serviço de acessibilidade agora também podem aumentar suas capacidades com as novas APIs que fornecem informações sobre conjuntos de visualizações, como visualizações de lista ou grade, usando AccessibilityNodeInfo.CollectionInfo e AccessibilityNodeInfo.CollectionItemInfo.

Permissões do aplicativo

As novas permissões a seguir são as que seu aplicativo deve 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 houver

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

Recursos do dispositivo

Os novos recursos de dispositivo a seguir são os que você pode declarar com a tag <uses-feature> para indicar os requisitos do seu aplicativo e ativar o recurso de filtro no Google Play ou verificá-los em tempo real:

FEATURE_CONSUMER_IR
O dispositivo é capaz de se comunicar com dispositivos de IR do consumidor.
FEATURE_DEVICE_ADMIN
O dispositivo apoia a imposição da política do dispositivo via administradores do dispositivo.
FEATURE_NFC_HOST_CARD_EMULATION
O dispositivo oferece compatibilidade com emulação de cartão NFC baseado em host.
FEATURE_SENSOR_STEP_COUNTER
O dispositivo inclui um aparelho contador de passos.
FEATURE_SENSOR_STEP_DETECTOR
O dispositivo inclui um aparelho detector de passos.

Para obter uma visualização detalhada de todas as alterações de API no Android 4.4, consulte o Relatório de diferenças das APIs.