Android 4.2 APIs

API de nível: 17

O Android 4.2 (JELLY_BEAN_MR1) é uma atualização da versão do Jelly Bean, que oferece novos recursos para usuários e desenvolvedores de apps. Este documento fornece uma introdução às novas APIs mais importantes e úteis para desenvolvedores.

Como desenvolvedor de apps, faça o download da imagem do sistema do Android 4.2 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.2 para testar o app, use a imagem do sistema Android 4.2 para testar o app no Android Emulator. Em seguida, crie seus aplicativos na plataforma Android 4.2 para começar a usar as APIs mais recentes.

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

Você pode usar APIs no Android 4.2 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 que não têm suporte da minSdkVersion. Para saber mais sobre como manter a compatibilidade com versões anteriores, leia Como criar IUs compatíveis com versões anteriores.

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

Mudanças de comportamento importantes

Se você já tiver publicado um app para Android, esteja ciente das seguintes mudanças que podem afetar o comportamento dele:

  • Por padrão, os provedores de conteúdo não são mais exportados. Ou seja, o valor padrão para o atributo android:exported agora é “false". Se for importante que outros apps acessem seu provedor de conteúdo, defina android:exported="true" explicitamente.

    Essa mudança só vai entrar em vigor se você definir android:targetSdkVersion ou android:minSdkVersion como 17 ou mais recente. Caso contrário, o valor padrão ainda será “true", mesmo quando executado no Android 4.2 e versões mais recentes.

  • Em comparação com versões anteriores do Android, os resultados da localização do usuário podem ser menos precisos se o app solicitar a permissão ACCESS_COARSE_LOCATION, mas não a ACCESS_FINE_LOCATION.

    Para atender às expectativas de privacidade dos usuários quando seu app solicita permissão para uma localização aproximada (e não para uma localização exata), o sistema não fornece uma estimativa de localização mais precisa do que um quarteirão.

  • Algumas configurações de dispositivo definidas por Settings.System agora são somente leitura. Se o app tentar gravar mudanças nas configurações definidas em Settings.System que foram movidas para Settings.Global, a operação de gravação falhará silenciosamente ao ser executada no Android 4.2 e versões mais recentes.

    Mesmo que o valor de android:targetSdkVersion e android:minSdkVersion seja menor que 17, o app não poderá modificar as configurações movidas para Settings.Global quando executado no Android 4.2 e versões mais recentes.

  • Se o app usa WebView, o Android 4.2 adiciona uma camada extra de segurança para que você possa vincular JavaScript ao código do Android com mais segurança. Se você definir o targetSdkVersion como 17 ou mais recente, adicione a anotação @JavascriptInterface a qualquer método que quiser disponibilizar para o JavaScript (o método também precisa ser público). Se você não fornecer a anotação, o método não poderá ser acessado por uma página da Web no WebView quando executado no Android 4.2 ou versões mais recentes. Se você definir a targetSdkVersion como 16 ou anterior, a anotação não será necessária, mas recomendamos que você atualize a versão de destino e adicione a anotação para aumentar a segurança.

    Leia mais sobre como vincular código JavaScript ao código Android.

Daydream

O Daydream é um novo modo de protetor de tela interativo para dispositivos Android. Ele é ativado automaticamente quando o dispositivo é inserido em uma base ou quando o dispositivo fica inativo enquanto está conectado a um carregador, em vez de desligar a tela. O Daydream exibe um sonho por vez, que pode ser uma tela puramente visual e passiva que é dispensada com o toque ou pode ser interativa e responsiva a um conjunto completo de eventos de entrada. Seus sonhos são executados no processo do app e têm acesso total ao kit de ferramentas de interface do Android, incluindo visualizações, layouts e animações. Por isso, eles são mais flexíveis e potentes do que planos de fundo interativos ou widgets de apps.

Você pode criar um sonho para o Daydream implementando uma subclasse de DreamService. As APIs DreamService foram projetadas para serem semelhantes às de Activity. Para especificar a interface do seu sonho, transmita um ID de recurso de layout ou View para setContentView() a qualquer momento depois que você tiver uma janela, como no callback onAttachedToWindow().

A classe DreamService fornece outros métodos de callback do ciclo de vida importantes sobre as APIs Service de base, como onDreamingStarted(), onDreamingStopped() e onDetachedFromWindow(). Não é possível iniciar um DreamService no app. Ele é iniciado automaticamente pelo sistema.

Se seu sonho é interativo, você pode iniciar uma atividade a partir dele para direcionar o usuário à interface completa do seu app para ter mais detalhes ou controle. Você pode usar finish() para encerrar o sonho para que o usuário possa conferir a nova atividade.

Para disponibilizar seu daydream para o sistema, declare seu DreamService com um elemento <service> no arquivo de manifesto. Em seguida, inclua um filtro de intent com a ação "android.service.dreams.DreamService". Por exemplo:

<service android:name=".MyDream" android:exported="true"
    android:icon="@drawable/dream_icon" android:label="@string/dream_label" >
    <intent-filter>
        <action android:name="android.service.dreams.DreamService" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</service>

Existem outros métodos úteis no DreamService que você precisa conhecer:

  • setInteractive(boolean) controla se o sonho recebe eventos de entrada ou sai imediatamente após a entrada do usuário. Se o sonho for interativo, o usuário poderá usar os botões Voltar ou Início para sair do sonho ou chamar finish() para interrompê-lo.
  • Se você quiser uma tela totalmente imersiva, chame setFullscreen() para ocultar a barra de status.
  • Antes de iniciar o Daydream, a tela escurece para sinalizar ao usuário que o tempo limite de inatividade está se aproximando. Chamar setScreenBright(true) permite que você defina a tela com o brilho normal.

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

Telas secundárias

O Android agora permite que seu app mostre conteúdo exclusivo em outras telas conectadas ao dispositivo do usuário por uma conexão com fio ou Wi-Fi. Para criar conteúdo exclusivo para uma tela secundária, estenda a classe Presentation e implemente o callback onCreate(). Em onCreate(), especifique a interface para a tela secundária chamando setContentView(). Como uma extensão da classe Dialog, a classe Presentation fornece a região em que seu app pode mostrar uma interface exclusiva na tela secundária.

Para detectar telas secundárias em que você pode mostrar o Presentation, use as APIs DisplayManager ou MediaRouter. Embora as APIs DisplayManager permitam enumerar várias telas que podem ser conectadas de uma só vez, geralmente é necessário usar MediaRouter para acessar rapidamente a tela padrão do sistema para apresentações.

Para exibir a tela padrão da apresentação, chame MediaRouter.getSelectedRoute() e transmita ROUTE_TYPE_LIVE_VIDEO a ele. Isso retorna um objeto MediaRouter.RouteInfo que descreve o trajeto selecionado do sistema para apresentações de vídeo. Se o MediaRouter.RouteInfo não for nulo, chame getPresentationDisplay() para receber o Display que representa a tela conectada.

Em seguida, você pode mostrar sua apresentação transmitindo o objeto Display a um construtor para a classe Presentation. Sua apresentação agora aparecerá na tela secundária.

Para detectar no momento da execução quando uma nova tela foi conectada, crie uma instância de MediaRouter.SimpleCallback na qual você implemente o método de callback onRoutePresentationDisplayChanged(), que o sistema chamará quando uma nova tela de apresentação for conectada. Em seguida, registre o MediaRouter.SimpleCallback transmitindo-o para MediaRouter.addCallback() com o tipo de rota ROUTE_TYPE_LIVE_VIDEO. Quando você receber uma chamada para onRoutePresentationDisplayChanged(), basta chamar MediaRouter.getSelectedRoute(), como mencionado acima.

Para otimizar ainda mais a interface na Presentation para telas secundárias, você pode aplicar um tema diferente especificando o atributo android:presentationTheme no <style> aplicado ao aplicativo ou à atividade.

Lembre-se de que as telas conectadas ao dispositivo do usuário geralmente têm um tamanho maior e provavelmente uma densidade diferente. Como as características da tela podem ser diferentes, forneça recursos otimizados especificamente para essas telas maiores. Se você precisar solicitar mais recursos do Presentation, chame getContext().getResources() para acessar o objeto Resources correspondente à tela. Isso fornece os recursos do app mais adequados ao tamanho e à densidade da tela secundária.

Para mais informações e alguns exemplos de código, consulte a documentação da classe Presentation.

Widgets da tela de bloqueio

O Android agora permite que os usuários adicionem widgets de apps à tela de bloqueio. Para disponibilizar seu widget de app para uso na tela de bloqueio, adicione o atributo android:widgetCategory ao arquivo XML que especifica o AppWidgetProviderInfo. Esse atributo aceita dois valores: home_screen e keyguard. Por padrão, o atributo é definido como home_screen para que os usuários possam adicionar seu widget de app à tela inicial. Se você quiser que o widget do app também esteja disponível na tela de bloqueio, adicione o valor keyguard:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:widgetCategory="keyguard|home_screen">
</appwidget-provider>

Também é necessário especificar um layout inicial para o widget de app na tela de bloqueio com o atributo android:initialKeyguardLayout. Isso funciona da mesma forma que o android:initialLayout, em que fornece um layout que pode aparecer imediatamente até que o widget do app seja inicializado e possa atualizar o layout.

Para mais informações sobre como criar widgets de apps para a tela de bloqueio, incluindo como dimensionar corretamente o widget na tela de bloqueio, consulte o guia Widgets de apps.

Vários usuários

O Android agora permite vários espaços do usuário em dispositivos compartilháveis, como tablets. Cada usuário em um dispositivo tem o próprio conjunto de contas, apps, configurações do sistema, arquivos e quaisquer outros dados associados ao usuário.

Como desenvolvedor, você não precisa fazer nada para que o app funcione corretamente com vários usuários em um único dispositivo. Independentemente de quantos usuários existem em um dispositivo, os dados que o app salva de um determinado usuário são mantidos separados dos dados que o app salva de outros usuários. O sistema monitora quais dados do usuário pertencem ao processo do usuário em que seu app está sendo executado e fornece ao app acesso apenas aos dados desse usuário, mas não permite acesso aos dados de outros usuários.

Como salvar dados em um ambiente multiusuário

Sempre que seu app salva as preferências do usuário, cria um banco de dados ou grava um arquivo no espaço de armazenamento interno ou externo do usuário, os dados ficam acessíveis apenas durante a execução como esse usuário.

Para garantir que seu app se comporte corretamente em um ambiente multiusuário, não use caminhos codificados para o diretório interno do app ou o local de armazenamento externo. Em vez disso, use sempre as APIs adequadas:

Não importa qual dessas APIs você usa para salvar dados de um determinado usuário, os dados não estarão acessíveis ao serem executados como um usuário diferente. Do ponto de vista do seu app, cada usuário está executando em um dispositivo completamente separado.

Como identificar usuários em um ambiente multiusuário

Se o app quiser identificar usuários únicos, por exemplo, para coletar análises ou criar outras associações de contas, siga as práticas recomendadas para identificar instalações únicas. Ao criar um novo UUID quando seu app for iniciado pela primeira vez, você certamente vai receber um ID exclusivo para rastrear cada usuário, independentemente de quantos usuários instalarem o app em um único dispositivo. Outra opção é salvar um token local buscado no seu servidor ou usar o ID de registros fornecido pelo Google Cloud Messaging.

Esteja ciente de que, se o app solicitar um dos identificadores de dispositivo de hardware (como o endereço MAC do Wi-Fi ou o número de SERIAL), eles vão fornecer o mesmo valor para cada usuário, porque esses identificadores estão vinculados ao hardware, e não ao usuário. Sem mencionar os outros problemas que esses identificadores apresentam, conforme discutido na postagem do blog Identificar instalações de apps.

Novas configurações globais

As configurações do sistema foram atualizadas para permitir vários usuários com a adição de Settings.Global. Esse conjunto de configurações é semelhante às configurações Settings.Secure porque são somente leitura, mas se aplicam globalmente a todos os espaços do usuário no dispositivo.

Várias configurações atuais foram realocadas aqui de Settings.System ou Settings.Secure. Se o app estiver fazendo mudanças nas configurações anteriormente definidas em Settings.System (como AIRPLANE_MODE_ON), essa ação não vai mais funcionar em um dispositivo com o Android 4.2 ou versões mais recentes se essas configurações forem movidas para Settings.Global. Você pode continuar lendo as configurações que estão em Settings.Global, mas, como as configurações não são mais consideradas seguras para que os apps mudem, a tentativa de fazer isso falhará silenciosamente, e o sistema gravará um aviso no registro do sistema ao executar o app no Android 4.2 ou mais recente.

Suporte a layout RTL

O Android agora oferece várias APIs que permitem criar interfaces do usuário que transformam de maneira eficiente a orientação do layout para oferecer suporte a idiomas que usam IUs da direita para a esquerda (RTL, na sigla em inglês) e direção de leitura, como árabe e hebraico.

Para começar a oferecer suporte a layouts RTL no seu app, defina o atributo android:supportsRtl como o elemento <application> no arquivo de manifesto e o defina como “true". Depois de ativar esse recurso, o sistema vai permitir que várias APIs RTL mostrem seu app com layouts RTL. Por exemplo, a barra de ações vai mostrar o ícone e o título no lado direito e os botões de ação à esquerda. Todos os layouts que você criou com as classes View fornecidas pelo framework também serão invertidos.

Se você precisa otimizar ainda mais a aparência do seu app quando exibido com um layout RTL, há dois níveis básicos de otimização:

  1. Converta propriedades de layout orientadas para a esquerda e para a direita em propriedades de layout orientadas para início e fim.

    Por exemplo, use android:layout_marginStart em vez de android:layout_marginLeft e android:layout_marginEnd no lugar de android:layout_marginRight.

    A classe RelativeLayout também fornece os atributos de layout correspondentes para substituir as posições esquerda/direita, por exemplo, android:layout_alignParentStart para substituir android:layout_alignParentLeft e android:layout_toStartOf em vez de android:layout_toLeftOf.

  2. Para oferecer otimização completa para layouts RTL, você pode fornecer arquivos de layout totalmente separados usando o qualificador de recurso ldrtl (ldrtl significa layout da direita para a esquerda}. Por exemplo, você pode salvar os arquivos de layout padrão em res/layout/ e os layouts otimizados para RTL em res/layout-ldrtl/.

    O qualificador ldrtl é ótimo para recursos drawable para que você possa fornecer gráficos orientados na direção correspondente à direção de leitura.

Várias outras APIs estão disponíveis em todo o framework para oferecer suporte a layouts RTL, como na classe View, para que você possa implementar os comportamentos adequados para visualizações personalizadas e em Configuration para consultar a direção atual do layout.

Observação:se você estiver usando o SQlite e tiver tabelas ou nomes de colunas "somente números", tenha cuidado: o uso de String.format(String, Object...) pode levar a erros em que os números foram convertidos para os equivalentes em árabe se o dispositivo tiver sido configurado para a localidade em árabe. Use String.format(Locale,String,Object...) para garantir que os números sejam preservados como ASCII. Use também String.format("%d", int) em vez de String.valueOf(int) para formatar números.

Fragments aninhados

Agora você pode incorporar fragmentos dentro de fragmentos. Isso é útil em várias situações em que você quer colocar componentes de interface dinâmicos e reutilizáveis em um componente de interface dinâmico e reutilizável. Por exemplo, se você usar ViewPager para criar fragmentos que deslizam para a esquerda e para a direita e consumam a maior parte do espaço da tela, agora será possível inserir fragmentos em cada página de fragmento.

Para aninhar um fragmento, basta chamar getChildFragmentManager() no Fragment em que você quer adicionar um fragmento. Isso retorna um FragmentManager que pode ser usado da mesma forma que é feito normalmente na atividade de nível superior para criar transações de fragmento. Por exemplo, confira este código que adiciona um fragmento de uma classe Fragment já existente:

Kotlin

val videoFragment = VideoPlayerFragment()
childFragmentManager.beginTransaction().apply {
    add(R.id.video_fragment, videoFragment)
    commit()
}

Java

Fragment videoFragment = new VideoPlayerFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(R.id.video_fragment, videoFragment).commit();

Em um fragmento aninhado, você pode conseguir uma referência ao fragmento pai chamando getParentFragment().

A Biblioteca de Suporte do Android agora também oferece suporte a fragmentos aninhados para que você possa implementar designs de fragmentos aninhados no Android 1.6 e em versões mais recentes.

Observação:não é possível inflar um layout em um fragmento quando esse layout inclui um <fragment>. Fragmentos aninhados só têm suporte quando são adicionados a um fragmento dinamicamente.

RenderScript

A funcionalidade de computação do Renderscript foi aprimorada com os seguintes recursos:

Intrínsecos do script

É possível usar os intrínsecos do script integrado do Renderscript que implementam operações comuns, como:

Para usar um script intrínseco, chame o método estático create() de cada intrínseco para criar uma instância do script. Em seguida, você chama os métodos set() disponíveis de cada intrínseco de script para definir as entradas e opções necessárias. Por fim, chame o método forEach() para executar o script.

Grupos de roteiros

ScriptGroups permitem encadear scripts Renderscript relacionados e executá-los com uma chamada.

Use um ScriptGroup.Builder para adicionar todos os scripts ao grupo chamando addKernel(). Depois de adicionar todos os scripts, crie as conexões entre eles chamando addConnection(). Quando terminar de adicionar as conexões, chame create() para criar o grupo de scripts. Antes de executar o grupo de scripts, especifique a entrada Allocation e o script inicial a ser executado com o método setInput(Script.KernelID, Allocation) e forneça a saída Allocation em que o resultado será gravado e o script final a ser executado com setOutput(). Por fim, chame execute() para executar o grupo de scripts.

Filterscript (em inglês)

O Filterscript define restrições nas APIs Renderscript existentes que permitem que o código resultante seja executado em uma variedade maior de processadores (CPUs, GPUs e DSPs). Para criar arquivos Filterscript, crie arquivos .fs em vez de .rs e especifique #pragma rs_fp_relaxed para informar ao ambiente de execução do Renderscript que seus scripts não exigem precisão de ponto flutuante IEEE 754-2008. Essa precisão permite a liberação de zero para desnormalização e arredondamento em direção a zero. Além disso, os scripts do Filterscript não podem usar tipos integrados de 32 bits e precisam especificar uma função raiz personalizada usando o atributo __attribute__((kernel)), já que o Filterscript não oferece suporte a ponteiros, que define a assinatura padrão da função root().

Observação:embora o suporte ao Filterscript esteja na plataforma, o suporte ao desenvolvedor está disponível na versão 21.0.1 das Ferramentas do SDK.

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