API de nível: 17
O Android 4.2 (JELLY_BEAN_MR1
)
é uma atualização da versão Jelly Bean. Ele 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, você precisa fazer 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 do Android 4.2 para testar o app no Android Emulator. Depois, 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 a targetSdkVersion
como
"17"
, instale-a 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 ainda oferecer suporte a versões mais antigas, adicionando
condições ao seu código que verifiquem 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 Como criar IUs compatíveis
com versões anteriores.
Para mais informações sobre como os níveis da API funcionam, consulte O que é o 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:
- Os provedores de conteúdo não são mais exportados por padrão. Ou seja, o valor padrão
para o atributo
android:exported
agora é“false"
. Se for importante que outros apps possam acessar seu provedor de conteúdo, agora você precisa definir explicitamenteandroid:exported="true"
.Essa mudança só vai entrar em vigor se você definir
android:targetSdkVersion
ouandroid: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 poderão ser menos precisos
se o app solicitar a permissão
ACCESS_COARSE_LOCATION
, mas não aACCESS_FINE_LOCATION
.Para atender às expectativas de privacidade dos usuários quando seu app solicita permissão para a localização aproximada (e não para a localização exata), o sistema não vai fornecer uma estimativa de localização do usuário mais precisa do que um quarteirão.
- Algumas configurações do dispositivo definidas por
Settings.System
agora são somente leitura. Se o app tentar gravar mudanças nas configurações definidas emSettings.System
que foram movidas paraSettings.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
eandroid:minSdkVersion
seja menor que 17, o app não poderá modificar as configurações movidas paraSettings.Global
ao ser executado no Android 4.2 e versões mais recentes. - Caso seu app use
WebView
, o Android 4.2 adiciona mais uma camada de segurança para que você possa vincular JavaScript ao código do Android com mais segurança. Se você definir suatargetSdkVersion
como 17 ou mais recente, será preciso adicionar 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 noWebView
quando executado no Android 4.2 ou mais recente. Se você definir atargetSdkVersion
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 do 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 ele 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 após o toque, ou pode ser interativa e responsiva para o pacote 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. Portanto, eles são mais flexíveis e poderosos 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 de abrir
uma janela, como no callback
onAttachedToWindow()
.
A classe DreamService
fornece outros métodos de callback do ciclo de vida
importantes, além das APIs Service
de base, como onDreamingStarted()
, onDreamingStopped()
e onDetachedFromWindow()
.
Não é possível iniciar um DreamService
pelo
app. Ele é iniciado automaticamente pelo sistema.
Se o sonho for interativo, você poderá 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 ver 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 alguns outros métodos úteis em 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 poderá chamarfinish()
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 habitual.
Para saber mais, consulte a documentação do DreamService
.
Telas secundárias
O Android agora permite que seu app exiba conteúdo exclusivo em telas adicionais que são 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 é possível mostrar o Presentation
,
use as APIs DisplayManager
ou
MediaRouter
. Embora as APIs DisplayManager
permitam enumerar
várias telas que podem estar conectadas de uma só vez, normalmente é necessário usar MediaRouter
para acessar rapidamente a exibição padrão do sistema para
apresentações.
Para usar a tela padrão da apresentação, chame MediaRouter.getSelectedRoute()
e transmita
ROUTE_TYPE_LIVE_VIDEO
. Isso retorna um objeto MediaRouter.RouteInfo
que descreve a rota selecionada no 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.
Você pode mostrar sua apresentação transmitindo o objeto Display
a um construtor da classe Presentation
. Sua apresentação aparecerá
na tela secundária.
Para detectar no momento da execução quando uma nova tela é conectada, crie uma instância de MediaRouter.SimpleCallback
em que implemente o método de callback onRoutePresentationDisplayChanged()
, que o sistema vai chamar quando uma nova
tela de apresentação for conectada. Em seguida, registre a MediaRouter.SimpleCallback
transmitindo-a 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>
que
aplicou 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 de tela diferente. Como as características da tela podem ser diferentes, forneça recursos otimizados especificamente para telas maiores. Se você precisar
solicitar mais recursos do Presentation
, chame getContext()
.getResources()
para receber o objeto Resources
correspondente à tela. Isso fornece
os recursos do app mais adequados ao
tamanho e à densidade da tela secundária da tela.
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 o
widget do 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>
Você também precisa 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
, já 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, inclusive para 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 de usuários 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 outros dados associados ao usuário.
Como desenvolvedor, você não precisa fazer nada diferente 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 para um determinado usuário são mantidos separados dos dados que o app salva para outros usuários. O sistema monitora quais dados do usuário pertencem ao processo do usuário em que o app está sendo executado e fornece ao app acesso apenas aos dados desse usuário, não permitindo o acesso aos dados de outros usuários.
Como salvar dados em um ambiente multiusuário
Sempre que seu app salva 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, esses dados só podem ser acessados durante a execução desse usuário.
Para ter certeza de que o app se comporta corretamente em um ambiente multiusuário, não consulte o diretório interno do app ou o local de armazenamento externo usando caminhos codificados. Em vez disso, sempre use as APIs adequadas:
- Para acessar o armazenamento interno, use
getFilesDir()
,getCacheDir()
ouopenFileOutput()
. - Para acessar o armazenamento externo, use
getExternalFilesDir()
ougetExternalStoragePublicDirectory()
.
Não importa qual dessas APIs você usa para salvar dados de um determinado usuário, os dados não poderão ser acessados durante a execução 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 reunir 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ê vai ter um ID exclusivo para rastrear cada usuário, independentemente de quantos
usuários instalarem o app em um único dispositivo. Como alternativa, você pode salvar um token local buscado no
seu servidor ou usar o ID de registro 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 fornecerão o mesmo valor para cada
usuário, porque esses identificadores estão vinculados ao hardware, e não ao usuário. Sem considerar 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 existentes foram realocadas aqui de Settings.System
ou Settings.Secure
. Se o app estiver
mudando as configurações definidas anteriormente 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 sejam alteradas, 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 suavemente 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 defina-o como “true"
. Depois de ativar isso, 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, e todos os layouts que você criou com as
classes View
fornecidas pelo framework também serão invertidos.
Se você precisar otimizar ainda mais a aparência do app quando exibido com um layout RTL, há dois níveis básicos de otimização:
- 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 deandroid:layout_marginLeft
eandroid:layout_marginEnd
em vez deandroid: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 substituirandroid:layout_alignParentLeft
eandroid:layout_toStartOf
em vez deandroid:layout_toLeftOf
. - Ou, para proporcionar 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 emres/layout/
e os layouts otimizados para RTL emres/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 nomes de tabelas ou colunas
"somente números", tenha
cuidado: o uso de String.format(String, Object...)
pode causar erros em que os números
foram convertidos para os equivalentes em árabe se o dispositivo tiver sido configurado para a localidade á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 IU dinâmicos e reutilizáveis em um componente de IU
dinâmico e reutilizável. Por exemplo, se você usar ViewPager
para
criar fragmentos que deslizam para a esquerda e para a direita e consuma a maior parte do espaço da tela, agora
poderá inserir fragmentos em cada página com fragmentos.
Para aninhar um fragmento, basta chamar getChildFragmentManager()
no
Fragment
em que você quer adicionar um. Isso retorna um FragmentManager
que pode ser usado como você faz normalmente na atividade de nível superior
para criar transações de fragmentos. Por exemplo, confira um código abaixo 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, é possível 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 versões mais recentes.
Observação:não é possível inflar um layout em um fragmento quando ele
inclui um <fragment>
. Os fragmentos aninhados só têm suporte quando são adicionados a um
fragmento dinamicamente.
RenderScript
A funcionalidade de computação de Renderscript foi aprimorada com os seguintes recursos:
- Intrínsecos do script
Você pode usar os intrínsecos do script integrado do Renderscript que implementam operações comuns, como:
Blends
Blur
Color matrix
3x3 convolve
5x5 convolve
Per-channel lookup table
Converting an Android YUV buffer to RGB
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, chame os métodosset()
disponíveis de cada intrínseco de script para definir as entradas e opções necessárias. Por fim, chame o métodoforEach()
para executar o script.- Grupos de scripts
-
ScriptGroup
s permitem encadear scripts Renderscript relacionados e executá-los com uma chamada.Use um
ScriptGroup.Builder
para adicionar todos os scripts ao grupo chamandoaddKernel()
. Depois de adicionar todos os scripts, crie as conexões entre eles chamandoaddConnection()
. Quando terminar de adicionar as conexões, chamecreate()
para criar o grupo de scripts. Antes de executar o grupo de scripts, especifique oAllocation
de entrada e o script inicial a ser executado com o métodosetInput(Script.KernelID, Allocation)
e forneça a saídaAllocation
em que o resultado será gravado e o script final a ser executado comsetOutput()
. Por fim, chameexecute()
para executar o grupo de scripts. - Filterscript (em inglês)
-
O Filterscript define restrições para as 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 uma precisão estrita de ponto flutuante IEEE 754-2008. Essa precisão permite uma liberação de zero para desnormas e arredondamentos em direção a zero. Além disso, os scripts 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 a assinatura padrão da funçãoroot()
define.
Observação:embora o suporte ao Filterscript esteja na plataforma, o suporte ao desenvolvedor está disponível nas Ferramentas do SDK versão 21.0.1.
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.