API de nível: 18
O Android 4.3 (JELLY_BEAN_MR2
) é 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.
Como desenvolvedor de apps, faça o download da imagem do sistema do Android 4.3 e da plataforma do SDK no SDK Manager o quanto antes. Se você não tiver um dispositivo com o Android 4.3 para testar o app, use a imagem do sistema do Android 4.3 para testar o app no Android Emulator. Em seguida, crie seus aplicativos na plataforma Android 4.3 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.3,
defina targetSdkVersion
como
"18"
, instale-o em uma imagem do sistema do Android 4.3,
teste e publique uma atualização com essa mudança.
Você pode usar APIs no Android 4.3 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 Compatibilidade com diferentes
versões da plataforma.
Várias APIs também estão disponíveis na Biblioteca de Suporte do Android, que permitem implementar novos recursos em versões mais antigas da plataforma.
Para mais informações sobre como os níveis da API funcionam, leia O que é um nível da API?.
Mudanças de comportamento importantes
Caso você já tenha publicado um app para Android, saiba que ele pode ser afetado pelas mudanças do Android 4.3.
Se o app usar intents implícitas...
Seu app pode ter um comportamento inadequado em um ambiente de perfil restrito.
Os usuários em um ambiente de perfil restrito podem não
ter todos os apps Android padrão disponíveis. Por exemplo, um perfil restrito pode desativar o
navegador da Web e o app de câmera. Portanto, seu app não pode fazer suposições sobre quais apps estão
disponíveis, porque se você chamar startActivity()
sem
verificar se um app está disponível para processar o Intent
,
seu app poderá falhar em um perfil restrito.
Ao usar uma intent implícita, você precisa sempre verificar se um app está disponível para processar a intent chamando resolveActivity()
ou queryIntentActivities()
. Por exemplo:
Kotlin
val intent = Intent(Intent.ACTION_SEND) ... if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show() }
Java
Intent intent = new Intent(Intent.ACTION_SEND); ... if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } else { Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show(); }
Se o app depende de contas...
Seu app pode ter um comportamento inadequado em um ambiente de perfil restrito.
Os usuários em um ambiente de perfil restrito não têm acesso a contas de usuário por padrão.
Se o app depender de um Account
, ele poderá falhar ou se comportar
inesperadamente em um perfil restrito.
Se você quiser impedir que perfis restritos usem seu app por completo porque ele
depende de informações confidenciais da conta, especifique o atributo android:requiredAccountType
no elemento
<application>
do manifesto.
Se você quiser permitir que perfis restritos continuem usando o app, mesmo sem poder criar contas próprias, desative os recursos do app que exigem uma conta ou permita que os perfis restritos acessem as contas criadas pelo usuário principal. Para mais informações, consulte a seção abaixo sobre Como oferecer suporte a contas em um perfil restrito.
Se o app usa o VideoView...
É possível que seu vídeo pareça menor no Android 4.3.
Nas versões anteriores do Android, o widget VideoView
calculou incorretamente o valor "wrap_content"
para layout_height
e layout_width
para ser igual a "match_parent"
. Portanto, mesmo que o uso de "wrap_content"
para a altura ou largura possa ter fornecido o layout de vídeo desejado,
fazer isso pode resultar em um vídeo muito menor no Android 4.3 e versões mais recentes. Para corrigir o problema, substitua
"wrap_content"
por "match_parent"
e verifique se o vídeo é exibido como esperado no
Android 4.3 e em versões mais antigas.
Perfis restritos
Em tablets Android, agora os usuários podem criar perfis restritos com base no usuário principal. Quando os usuários criam um perfil restrito, eles podem ativar restrições, como quais apps estão disponíveis para o perfil. Um novo conjunto de APIs no Android 4.3 também permite que você crie configurações de restrição detalhadas para os apps que desenvolver. Por exemplo, usando as novas APIs, você pode permitir que os usuários controlem o tipo de conteúdo disponível no app quando executado em um ambiente de perfil restrito.
A interface para que os usuários controlem as restrições que você criou é gerenciada pelo aplicativo
Configurações do sistema. Para que as configurações de restrição do seu app apareçam para o usuário,
é necessário declarar as restrições oferecidas pelo app, criando um BroadcastReceiver
que receba a intent ACTION_GET_RESTRICTION_ENTRIES
. O sistema invoca essa intent para consultar
todos os apps em busca das restrições disponíveis e, em seguida, cria a interface para permitir que o usuário principal
gerencie restrições de cada perfil restrito.
No método onReceive()
da
BroadcastReceiver
, é necessário criar uma RestrictionEntry
para cada restrição fornecida pelo app. Cada RestrictionEntry
define um título de restrição, uma descrição e um dos
tipos de dados abaixo:
TYPE_BOOLEAN
para uma restrição que seja verdadeira ou falsa.TYPE_CHOICE
para uma restrição com várias opções que são mutuamente exclusivas (opções de botão).TYPE_MULTI_SELECT
para uma restrição com várias opções que não são mutuamente exclusivas (opções de caixa de seleção).
Em seguida, você coloca todos os objetos RestrictionEntry
em uma ArrayList
e a coloca no resultado do broadcast receiver como o valor do
extra EXTRA_RESTRICTIONS_LIST
.
O sistema cria a interface para as restrições do app no app Configurações e salva cada
restrição com a chave exclusiva fornecida para cada objeto
RestrictionEntry
. Quando o usuário abre seu app, você pode consultar as restrições atuais
chamando getApplicationRestrictions()
.
Isso retorna um Bundle
contendo os pares de chave-valor para cada restrição definida com os objetos RestrictionEntry
.
Se você quiser fornecer restrições mais específicas que não possam ser processadas por valores booleanos, de escolha
única e de múltipla escolha, crie uma atividade em que o usuário possa especificar as
restrições e permitir que eles abram essa atividade nas configurações de restrição. No
broadcast receiver, inclua o extra EXTRA_RESTRICTIONS_INTENT
no resultado Bundle
. Esse extra precisa especificar um Intent
indicando a classe Activity
a ser iniciada. Use o
método putParcelable()
para transmitir EXTRA_RESTRICTIONS_INTENT
com a intent.
Quando o usuário principal insere sua atividade para definir restrições personalizadas, ela
precisa retornar um resultado contendo os valores de restrição em um extra usando
a chave EXTRA_RESTRICTIONS_LIST
ou EXTRA_RESTRICTIONS_BUNDLE
, dependendo se você especifica
objetos RestrictionEntry
ou pares de chave-valor, respectivamente.
Como oferecer suporte a contas em um perfil restrito
Todas as contas adicionadas ao usuário principal ficam disponíveis para um perfil restrito, mas
não podem ser acessadas nas APIs AccountManager
por padrão.
Se você tentar adicionar uma conta com AccountManager
em um perfil restrito, vai receber um resultado de falha. Devido a essas restrições, você tem três opções:
Para acessar uma conta de um perfil restrito, adicione o atributo android:restrictedAccountType
à tag <application>:
<application ... android:restrictedAccountType="com.example.account.type" >
Cuidado:a ativação desse atributo permite que o app acesse as contas do usuário principal em perfis restritos. Portanto, permita isso somente se as informações exibidas pelo app não revelarem informações de identificação pessoal (PII) consideradas confidenciais. As configurações do sistema informarão ao usuário principal que o app concede perfis restritos às contas. Por isso, fica claro para o usuário que o acesso à conta é importante para a funcionalidade do app. Se possível, forneça também controles de restrição adequados para o usuário principal que definam quanto acesso à conta é permitido no app.
Se você quiser usar contas, mas não precisar delas para a funcionalidade
principal do app, verifique a disponibilidade da conta e desative os recursos quando não estiverem disponíveis.
Primeiro, verifique se já existe uma conta disponível. Caso contrário, consulte
se é possível criar uma nova conta chamando getUserRestrictions()
e verifique o extra DISALLOW_MODIFY_ACCOUNTS
no resultado. Se for true
,
desative qualquer funcionalidade do app que exija acesso às contas.
Por exemplo:
Kotlin
val um = context.getSystemService(Context.USER_SERVICE) as UserManager val restrictions: Bundle = um.userRestrictions if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Java
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { // cannot add accounts, disable some functionality }
Observação:nesse cenário, não declare nenhum novo atributo no arquivo de manifesto.
Se for importante que o app não esteja disponível para perfis restritos porque
ele depende de informações pessoais sensíveis em uma conta (e porque perfis restritos
atualmente não podem adicionar novas contas), adicione
o atributo android:requiredAccountType
à tag <application>:
<application ... android:requiredAccountType="com.example.account.type" >
Por exemplo, o app Gmail usa esse atributo para se desativar em perfis restritos, porque o e-mail pessoal do proprietário não pode estar disponível para perfis restritos.
Redes sem fio e conectividade
Bluetooth de baixa energia (Smart Ready)
O Android agora oferece suporte ao Bluetooth de baixa energia (LE, na sigla em inglês) com novas APIs em android.bluetooth
.
Com as novas APIs, você pode criar apps Android que se comunicam com periféricos Bluetooth de baixa energia,
como monitores de frequência cardíaca e pedômetros.
Como o Bluetooth LE é um recurso de hardware que não está disponível em todos
os dispositivos Android, é necessário declarar no arquivo de manifesto um elemento <uses-feature>
para "android.hardware.bluetooth_le"
:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
Se você já conhece as APIs Classic Bluetooth do Android, observe que o uso das
APIs Bluetooth LE tem algumas diferenças. O mais importante é que agora existe uma classe BluetoothManager
que precisa ser usada para algumas operações de alto nível, como adquirir um BluetoothAdapter
, acessar uma lista de dispositivos
conectados e verificar o estado de um dispositivo. Por exemplo, veja como você precisa receber o
BluetoothAdapter
:
Kotlin
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager bluetoothAdapter = bluetoothManager.adapter
Java
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter();
Para descobrir periféricos Bluetooth LE, chame startLeScan()
no BluetoothAdapter
, transmitindo uma implementação
da interface BluetoothAdapter.LeScanCallback
. Quando o adaptador Bluetooth
detecta um periférico Bluetooth LE, a implementação BluetoothAdapter.LeScanCallback
recebe uma chamada para o
método onLeScan()
. Esse
método fornece um objeto BluetoothDevice
que representa o
dispositivo detectado, o valor RSSI do dispositivo e uma matriz de bytes contendo o registro de divulgação
do dispositivo.
Se você quiser procurar apenas tipos específicos de periféricos, chame startLeScan()
e inclua uma matriz de objetos UUID
que especifiquem os serviços GATT compatíveis com o app.
Observação:só é possível procurar dispositivos Bluetooth LE ou procurar dispositivos Bluetooth clássico usando APIs anteriores. Não é possível procurar dispositivos Bluetooth LE e Classic ao mesmo tempo.
Para se conectar a um periférico Bluetooth LE, chame connectGatt()
no objeto
BluetoothDevice
correspondente, transmitindo uma implementação de
BluetoothGattCallback
. Sua implementação de BluetoothGattCallback
recebe callbacks sobre o estado de
conectividade com o dispositivo e outros eventos. É durante o callback onConnectionStateChange()
que você pode começar a se comunicar com o dispositivo se o método transmitir STATE_CONNECTED
como o novo estado.
O acesso a recursos Bluetooth em um dispositivo também exige que o app solicite determinadas permissões de usuário do Bluetooth. Para ver mais informações, consulte o guia da API Bluetooth Low Energy.
Modo somente busca por Wi-Fi
Ao tentar identificar a localização do usuário, o Android pode usar o Wi-Fi para determinar a localização, verificando pontos de acesso por perto. No entanto, os usuários geralmente mantêm o Wi-Fi desativado para economizar bateria, o que resulta em dados de localização menos precisos. O Android agora inclui um modo somente leitura que permite que o Wi-Fi do dispositivo procure pontos de acesso para ajudar a receber a localização sem se conectar a um ponto de acesso, reduzindo significativamente o uso da bateria.
Se você quiser acessar a localização do usuário, mas o Wi-Fi estiver desativado no momento, solicite que o
usuário ative o modo somente busca por Wi-Fi chamando startActivity()
com a ação ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
.
Configuração do Wi-Fi
As novas APIs WifiEnterpriseConfig
permitem que serviços empresariais
automatizem a configuração de Wi-Fi para dispositivos gerenciados.
Resposta rápida para ligações recebidas
Desde o Android 4.0, um recurso chamado "Resposta rápida" permite que os usuários respondam a chamadas
recebidas com uma mensagem de texto imediata, sem precisar atender a chamada ou desbloquear o dispositivo.
Até agora, essas mensagens rápidas sempre eram processadas pelo app Mensagens padrão. Agora qualquer app
pode declarar a própria capacidade de lidar com essas mensagens criando um Service
com um filtro de intent para ACTION_RESPOND_VIA_MESSAGE
.
Quando o usuário responde a uma chamada recebida com uma resposta rápida, o app Telefone envia
a intent ACTION_RESPOND_VIA_MESSAGE
com um URI
que descreve o destinatário (o autor da chamada) e o extra EXTRA_TEXT
com a mensagem que o usuário quer enviar. Ao receber a intent, o serviço precisa entregar
a mensagem e ser interrompido imediatamente. Seu app não pode mostrar uma atividade.
Para receber essa intent, declare a permissão SEND_RESPOND_VIA_MESSAGE
.
Multimídia
Melhorias do MediaExtractor e MediaCodec
Usando as APIs existentes em MediaCodec
e MediaExtractor
, o Android agora facilita a criação de seus próprios players de streaming adaptável dinâmico sobre HTTP (DASH), de acordo com o padrão ISO/IEC 23009-1. O framework de base dessas APIs foi atualizado para oferecer suporte à
análise de arquivos MP4 fragmentados, mas seu app ainda é responsável por analisar os metadados da MPD
e transmitir os streams individuais para MediaExtractor
.
Se você quiser usar o DASH com conteúdo criptografado, observe que o método getSampleCryptoInfo()
retorna os metadados MediaCodec.CryptoInfo
que descrevem a estrutura de cada amostra de mídia
criptografada. Além disso, o método getPsshInfo()
foi adicionado a
MediaExtractor
para que você possa acessar os metadados PSSH da sua mídia DASH.
Esse método retorna um mapa de objetos UUID
para bytes, com o
UUID
especificando o esquema de criptografia, e os bytes sendo os dados específicos
desse esquema.
DRM de mídia
A nova classe MediaDrm
fornece uma solução modular para o gerenciamento de direitos
digitais (DRM, na sigla em inglês) com seu conteúdo de mídia, separando as preocupações com o DRM da reprodução de mídia. Por
exemplo, essa separação de API permite reproduzir conteúdo criptografado pelo Widevine sem precisar
usar o formato de mídia Widevine. Essa solução de DRM também oferece suporte à criptografia comum do DASH para que você
possa usar vários esquemas de DRM com seu conteúdo de streaming.
É possível usar MediaDrm
para receber mensagens opacas de solicitação de chave e processar mensagens de resposta de chave do servidor para aquisição e provisionamento de licenças. Seu app é
responsável por processar a comunicação de rede com os servidores. A classe MediaDrm
oferece apenas a capacidade de gerar e processar as mensagens.
As APIs MediaDrm
precisam ser usadas em conjunto com as
APIs MediaCodec
introduzidas no Android 4.1 (nível 16 da API),
incluindo MediaCodec
para codificar e decodificar seu conteúdo, MediaCrypto
para processar conteúdo criptografado e MediaExtractor
para extrair e remover multiplexação do conteúdo.
Primeiro, construa os objetos MediaExtractor
e
MediaCodec
. Você pode acessar o UUID
de identificação de esquema
de DRM, normalmente de metadados no conteúdo, e usá-lo para construir uma
instância de um objeto MediaDrm
com o respectivo construtor.
Codificação de vídeo de uma superfície
O Android 4.1 (API de nível 16) adicionou a classe MediaCodec
para codificação
e decodificação de baixo nível de conteúdo de mídia. Ao codificar vídeos, o Android 4.1 exigia que você fornecesse
à mídia uma matriz ByteBuffer
, mas o Android 4.3 agora permite usar um Surface
como entrada para um codificador. Por exemplo, isso permite codificar a entrada
de um arquivo de vídeo existente ou usar frames gerados pelo OpenGL ES.
Se quiser usar um Surface
como entrada para o codificador, chame configure()
para o MediaCodec
.
Em seguida, chame createInputSurface()
para receber o Surface
em que você pode fazer streaming da mídia.
Por exemplo, você pode usar a Surface
especificada como a janela de um contexto
do OpenGL, transmitindo-a para eglCreateWindowSurface()
. Em seguida, ao renderizar a superfície, chame eglSwapBuffers()
para transmitir o frame ao MediaCodec
.
Para começar a codificação, chame start()
no MediaCodec
. Quando terminar, chame signalEndOfInputStream()
para encerrar a codificação e chame release()
no
Surface
.
Mixagem de mídia
A nova classe MediaMuxer
permite a multiplexação entre um stream de áudio
e um stream de vídeo. Essas APIs servem como uma contraparte da classe MediaExtractor
adicionada no Android 4.2 para desmultiplexação (deemuxação) de mídia.
Os formatos de saída compatíveis são definidos em MediaMuxer.OutputFormat
. Atualmente,
MP4 é o único formato de saída aceito, e MediaMuxer
aceita
apenas um stream de áudio e/ou um stream de vídeo por vez.
MediaMuxer
foi projetado principalmente para funcionar com MediaCodec
para que você possa executar o processamento de vídeo por MediaCodec
e, em seguida, salvar a saída em um arquivo MP4 por meio de MediaMuxer
. Você também pode usar MediaMuxer
em combinação com MediaExtractor
para executar
a edição de mídia sem precisar codificar ou decodificar.
Progresso da reprodução e refinamento para RemoteControlClient
No Android 4.0 (API de nível 14), a RemoteControlClient
foi adicionada para
ativar controles de reprodução de mídia de clientes de controle remoto, como os controles disponíveis na
tela de bloqueio. O Android 4.3 agora oferece a esses controles a capacidade de exibir a posição de reprodução
e os controles para refinar a reprodução. Se você ativou o controle remoto para seu
app de música com as APIs RemoteControlClient
, pode permitir a barra de reprodução
implementando duas novas interfaces.
Primeiro, é necessário ativar a flag FLAG_KEY_MEDIA_POSITION_UPDATE
transmitindo-a para
setTransportControlsFlags()
.
Em seguida, implemente estas duas novas interfaces:
RemoteControlClient.OnGetPlaybackPositionListener
- Isso inclui o callback
onGetPlaybackPosition()
, que solicita a posição atual da mídia quando o controle remoto precisa atualizar o progresso na interface. RemoteControlClient.OnPlaybackPositionUpdateListener
- Isso inclui o callback
onPlaybackPositionUpdate()
, que informa ao app o novo código de tempo da mídia quando o usuário clica na reprodução com a interface do controle remoto.Depois de atualizar a reprodução com a nova posição, chame
setPlaybackState()
para indicar o novo estado, posição e velocidade da reprodução.
Com essas interfaces definidas, você pode defini-las para RemoteControlClient
chamando setOnGetPlaybackPositionListener()
e
setPlaybackPositionUpdateListener()
, respectivamente.
Gráficos
Suporte para OpenGL ES 3.0
O Android 4.3 adiciona interfaces Java e suporte nativo para OpenGL ES 3.0. As principais novas funcionalidades fornecidas no OpenGL ES 3.0 incluem:
- Aceleração de efeitos visuais avançados
- Compactação de textura ETC2/EAC de alta qualidade como recurso padrão
- Uma nova versão da linguagem de sombreamento GLSL ES com suporte a números inteiros e ponto flutuante de 32 bits
- Renderização avançada de textura
- Padronização mais ampla de tamanho de textura e formatos de buffer de renderização
A interface Java para OpenGL ES 3.0 no Android é fornecida com GLES30
.
Ao usar o OpenGL ES 3.0, declare isso no arquivo de manifesto com a tag
<uses-feature>
e o atributo android:glEsVersion
. Por exemplo:
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
Lembre-se de especificar o contexto do OpenGL ES chamando setEGLContextClientVersion()
,
transmitindo 3
como a versão.
Para mais informações sobre como usar o OpenGL ES, inclusive como verificar a versão do OpenGL ES compatível no dispositivo durante a execução, consulte o guia da API OpenGL ES.
Mipmapping para drawables
Usar um mipmap como origem para bitmap ou drawable é uma maneira simples de fornecer uma imagem de qualidade e várias escalas de imagem, o que pode ser particularmente útil se você espera que a imagem seja dimensionada durante uma animação.
O Android 4.2 (API de nível 17) adicionou suporte a mipmaps na classe
Bitmap
. O Android troca as imagens mip no Bitmap
quando você
fornece uma fonte de mipmap e ativa setHasMipMap()
. Agora, no Android 4.3, também é possível ativar mipmaps para um objeto BitmapDrawable
fornecendo um recurso de mipmap e
definindo o atributo android:mipMap
em um arquivo de recurso de bitmap ou chamando hasMipMap()
.
Interface do usuário
Ver sobreposições
A nova classe ViewOverlay
fornece uma camada transparente sobre
uma View
em que você pode adicionar conteúdo visual e que não afeta
a hierarquia de layout. Você pode ter um ViewOverlay
para qualquer View
chamando getOverlay()
. A sobreposição
sempre tem o mesmo tamanho e posição que a visualização host (a visualização da qual ela foi criada),
permitindo que você adicione conteúdo que aparece na frente dela, mas que não pode estender
os limites dessa visualização.
O uso de um ViewOverlay
é particularmente útil quando você quer criar
animações, como deslizar uma visualização para fora do contêiner ou mover itens pela tela
sem afetar a hierarquia de visualização. No entanto, como a área utilizável de uma sobreposição está
restrita à mesma área que a visualização host, se você quiser animar uma visualização se movendo
para fora da posição no layout, use uma sobreposição de uma visualização mãe que tenha os limites
de layout desejados.
Ao criar uma sobreposição para uma visualização de widget, como Button
, você
pode adicionar objetos Drawable
à sobreposição chamando
add(Drawable)
. Se você chamar getOverlay()
para uma visualização de layout, como RelativeLayout
,
o objeto retornado será um ViewGroupOverlay
. A
classe ViewGroupOverlay
é uma subclasse
de ViewOverlay
que também permite adicionar objetos View
chamando add(View)
.
Observação:todos os drawables e visualizações adicionados a uma sobreposição são apenas visuais. Eles não podem receber eventos de foco ou de entrada.
Por exemplo, o código a seguir anima uma visualização deslizando para a direita posicionando a visualização na sobreposição da visualização mãe e executando uma animação de translação nessa visualização:
Kotlin
val view: View? = findViewById(R.id.view_to_remove) val container: ViewGroup? = view?.parent as ViewGroup container?.apply { overlay.add(view) ObjectAnimator.ofFloat(view, "translationX", right.toFloat()) .start() }
Java
View view = findViewById(R.id.view_to_remove); ViewGroup container = (ViewGroup) view.getParent(); container.getOverlay().add(view); ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight()); anim.start();
Layout de limites ópticos
Para visualizações que contêm imagens de plano de fundo Nine-Patch, agora você pode especificar que elas precisam ser alinhadas com visualizações vizinhas com base nos limites "ópticos" da imagem de plano de fundo em vez dos limites de "recorte" da visualização.
Por exemplo, as figuras 1 e 2 mostram o mesmo layout, mas a versão na figura 1 está usando limites de corte (o comportamento padrão), enquanto a figura 2 usa limites ópticos. Como as imagens Nine-Patch usadas para o botão e o Porta-retratos incluem padding ao redor das bordas, elas não parecem estar alinhadas entre si ou com o texto ao usar limites de corte.
Observação:nas capturas de tela das figuras 1 e 2, a configuração do desenvolvedor "Mostrar limites de layout" está ativada. Para cada visualização, linhas vermelhas indicam os limites ópticos, linhas azuis indicam os limites de corte e rosa indica margens.
![](https://developer.android.com/static/images/tools/clipbounds_2x.png?authuser=7&hl=pt)
Figura 1. Layout que usa limites de corte (padrão).
![](https://developer.android.com/static/images/tools/opticalbounds_2x.png?authuser=7&hl=pt)
Figura 2. Layout que usa limites ópticos.
Para alinhar as visualizações com base nos limites ópticos, defina o atributo android:layoutMode
como "opticalBounds"
em um dos layouts pai. Por exemplo:
<LinearLayout android:layoutMode="opticalBounds" ... >
![](https://developer.android.com/static/images/tools/ninepatch_opticalbounds_2x.png?authuser=7&hl=pt)
Figura 3. Visualização ampliada do Nine-Patch do botão Holo com limites ópticos.
Para que isso funcione, as imagens Nine-Patch aplicadas ao plano de fundo das suas visualizações precisam especificar os limites ópticos usando linhas vermelhas ao longo das partes inferior e direita do arquivo Nine-Patch (como mostrado na Figura 3). As linhas vermelhas indicam a região que precisa ser subtraída dos limites de corte, deixando os limites ópticos da imagem.
Quando você ativa os limites ópticos para uma ViewGroup
no layout, todas
as visualizações descendentes herdam o modo de layout de limites ópticos, a menos que você o substitua para um grupo,
definindo android:layoutMode
como "clipBounds"
. Todos os elementos de layout também respeitam os
limites ópticos das visualizações filhas, adaptando os próprios limites com base nos limites ópticos
das visualizações dentro deles. No entanto, os elementos de layout (subclasses de ViewGroup
)
atualmente não oferecem suporte a limites ópticos para imagens Nine-Patch aplicadas ao próprio plano de fundo.
Se você criar uma visualização personalizada subdividindo View
, ViewGroup
ou qualquer outra subclasse, a visualização vai herdar esses comportamentos de limitação óptica.
Observação:todos os widgets com suporte ao tema Holo foram atualizados
com limites ópticos, incluindo Button
, Spinner
,
EditText
e outros. Assim, você pode se beneficiar imediatamente definindo o
atributo android:layoutMode
como "opticalBounds"
se o app aplicar um tema Holo
(Theme.Holo
, Theme.Holo.Light
etc.).
Para especificar limites ópticos para suas próprias imagens Nine-Patch com a ferramenta Draw 9-patch, mantenha a tecla Control pressionada ao clicar nos pixels da borda.
Animação para valores Rect
Agora você pode animar entre dois valores Rect
com o novo RectEvaluator
Essa nova classe é uma implementação de TypeEvaluator
que você pode transmitir para ValueAnimator.setEvaluator()
.
Listener de anexação e foco de janela
Antes, se você quisesse detectar quando sua visualização foi anexada/desanexada à janela ou
quando o foco mudava, era necessário substituir a classe View
para
implementar onAttachedToWindow()
e onDetachedFromWindow()
ou onWindowFocusChanged()
, respectivamente.
Agora, para receber eventos de anexação e remoção, implemente ViewTreeObserver.OnWindowAttachListener
e defina-o em uma visualização com
addOnWindowAttachListener()
.
Para receber eventos de foco, você pode implementar ViewTreeObserver.OnWindowFocusChangeListener
e defini-lo em uma visualização com
addOnWindowFocusChangeListener()
.
Suporte a overscan de TV
Para garantir que o app preencha toda a tela em todas as televisões, agora você pode ativar o overscan
no layout do app. O modo overscan é determinado pela flag FLAG_LAYOUT_IN_OVERSCAN
, que pode ser ativada com temas de plataforma como
Theme_DeviceDefault_NoActionBar_Overscan
ou ativando o
estilo windowOverscan
em um tema personalizado.
Orientação da tela
O atributo screenOrientation
da tag <activity>
agora aceita mais valores para respeitar a preferência do usuário pela rotação automática:
"userLandscape"
- Se comporta da mesma forma que
"sensorLandscape"
, exceto se o usuário desativar o giro automático, ele bloquear na orientação normal de paisagem e não virar. "userPortrait"
- Se comporta da mesma forma que
"sensorPortrait"
, exceto se o usuário desativar o giro automático e, em seguida, ele ficar bloqueado na orientação normal de retrato e não virar. "fullUser"
- Se comporta como
"fullSensor"
e permite a rotação em todas as quatro direções, exceto se o usuário desativar o giro automático, ele será bloqueado na orientação preferida do usuário.
Além disso, agora você também pode declarar "locked"
para bloquear a orientação do app na
orientação atual da tela.
Animações de rotação
O novo campo rotationAnimation
em
WindowManager
permite selecionar uma das três animações que você
quer usar quando o sistema mudar a orientação da tela. As três animações são:
Observação:essas animações estão disponíveis somente se você configurou a atividade para usar o modo "tela cheia", que pode ser ativado com temas como Theme.Holo.NoActionBar.Fullscreen
.
Por exemplo, veja como ativar a animação de "crossfade":
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val params: WindowManager.LayoutParams = window.attributes params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE window.attributes = params ... }
Java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowManager.LayoutParams params = getWindow().getAttributes(); params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; getWindow().setAttributes(params); ... }
Entrada do usuário
Novos tipos de sensor
O novo sensor TYPE_GAME_ROTATION_VECTOR
permite detectar as rotações do dispositivo sem se preocupar com interferências magnéticas. Ao contrário do sensor TYPE_ROTATION_VECTOR
, o TYPE_GAME_ROTATION_VECTOR
não se baseia no norte magnético.
Os novos sensores TYPE_GYROSCOPE_UNCALIBRATED
e TYPE_MAGNETIC_FIELD_UNCALIBRATED
fornecem dados brutos do sensor sem
considerar estimativas de viés. Ou seja, os sensores TYPE_GYROSCOPE
e TYPE_MAGNETIC_FIELD
atuais fornecem dados que consideram o viés estimado do giroscópio e do ferro duro
no dispositivo, respectivamente. Já as novas versões "não calibradas" desses sensores fornecem
os dados brutos do sensor e os valores de viés estimados separadamente. Esses sensores permitem que você
forneça uma calibração personalizada para os dados do sensor, melhorando o viés estimado com
dados externos.
Listener de notificações
O Android 4.3 adiciona uma nova classe de serviço, NotificationListenerService
, que permite que o aplicativo receba informações sobre novas notificações à medida que são postadas pelo sistema.
Se o seu app usa as APIs de serviço de acessibilidade para acessar notificações do sistema, ele precisa ser atualizado para usar essas APIs.
Provedor de contatos
Consulta para "contactable"
A nova consulta do Provedor de contatos, Contactables.CONTENT_URI
, é uma forma eficiente de ter um Cursor
que contenha todos os endereços de e-mail e números de telefone de todos os contatos que correspondam à consulta especificada.
Consultar deltas de contatos
Novas APIs foram adicionadas ao Provedor de contatos, permitindo que você consulte de forma eficiente alterações recentes nos dados dos contatos. Antes, seu app podia ser notificado quando algo nos dados de contatos mudava, mas você não sabia exatamente o que havia sido alterado e precisaria recuperar todos os contatos e, em seguida, interagir com eles para descobrir a alteração.
Para acompanhar as mudanças em inserções e atualizações, agora é possível incluir o parâmetro CONTACT_LAST_UPDATED_TIMESTAMP
com sua seleção para consultar apenas os contatos que mudaram desde a última vez que você consultou o provedor.
Para monitorar quais contatos foram excluídos, a nova tabela ContactsContract.DeletedContacts
fornece um registro dos contatos que foram excluídos, mas cada contato excluído é mantido nessa tabela por tempo limitado. Assim como em CONTACT_LAST_UPDATED_TIMESTAMP
, é possível usar o novo parâmetro de seleção, CONTACT_DELETED_TIMESTAMP
, para conferir quais contatos foram excluídos desde a última consulta com o provedor. A tabela também contém a constante DAYS_KEPT_MILLISECONDS
que contém o número de dias (em milissegundos) em que o registro será mantido.
Além disso, o Provedor de contatos agora transmite a ação CONTACTS_DATABASE_CREATED
quando o usuário
limpa o armazenamento de contatos no menu de configurações do sistema, recriando efetivamente o
banco de dados do Provedor de contatos. O objetivo é sinalizar aos apps que eles precisam descartar todos os dados de contato
armazenados e recarregá-los com uma nova consulta.
Para ver um exemplo de código usando essas APIs para verificar se há alterações nos contatos, consulte o exemplo ApiDemos disponível no download de Amostras do SDK.
Localização
Compatibilidade aprimorada com texto bidirecional
As versões anteriores do Android oferecem suporte a idiomas e layout da direita para a esquerda (RTL, na sigla em inglês),
mas às vezes não processam corretamente textos em direção mista. O Android 4.3 adiciona as APIs BidiFormatter
, que ajudam a formatar corretamente o texto com conteúdo de direção oposta
sem atrapalhar nenhuma parte dele.
Por exemplo, quando você quer criar uma frase com uma variável de string, como "Você quis dizer
15 Bay Street, Laurel, CA?", normalmente transmite um recurso de string localizado e a variável para
String.format()
:
Kotlin
val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
Java
Resources res = getResources(); String suggestion = String.format(res.getString(R.string.did_you_mean), address);
No entanto, se a localidade for em hebraico, a string formatada ficará assim:
האם התכוונת ל 15 Bay Street, Laurel, CA?
Incorreto. O número "15" deveria ser deixado de "Bay Street". A solução é usar BidiFormatter
e o método unicodeWrap()
. Por exemplo, o código acima se torna:
Kotlin
val bidiFormatter = BidiFormatter.getInstance() val suggestion = String.format( resources.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address) )
Java
Resources res = getResources(); BidiFormatter bidiFormatter = BidiFormatter.getInstance(); String suggestion = String.format(res.getString(R.string.did_you_mean), bidiFormatter.unicodeWrap(address));
Por padrão, unicodeWrap()
usa a
primeira heurística de estimativa de direção forte, o que pode dar errado se o primeiro
indicador de direção do texto não representar a direção apropriada para o conteúdo como um todo.
Se necessário, você pode especificar uma heurística diferente transmitindo uma das constantes TextDirectionHeuristic
de TextDirectionHeuristics
para unicodeWrap()
.
Observação:essas novas APIs também estão disponíveis para versões anteriores
do Android na Biblioteca de
Suporte do Android, com a classe BidiFormatter
e APIs relacionadas.
Serviços de acessibilidade
Gerenciar eventos de teclas
Um AccessibilityService
agora pode receber um callback para
eventos de entrada de teclas com o método de callback onKeyEvent()
. Isso permite que o serviço de acessibilidade processe entradas para
dispositivos de entrada baseados em teclas, como um teclado, e traduza esses eventos em ações especiais que
anteriormente podiam ser feitas apenas com a entrada por toque ou o botão direcional do dispositivo.
Selecionar texto e copiar/colar
O AccessibilityNodeInfo
agora fornece APIs que permitem
que um AccessibilityService
selecione, recorte, copie e cole
texto em um nó.
Para especificar a seleção de texto a ser cortado ou copiado, seu serviço de acessibilidade pode usar a nova
ação, ACTION_SET_SELECTION
, transmitindo
com ACTION_ARGUMENT_SELECTION_START_INT
e ACTION_ARGUMENT_SELECTION_END_INT
as posições de início e término da seleção.
Como alternativa, selecione o texto manipulando a posição do cursor usando a ação existente, ACTION_NEXT_AT_MOVEMENT_GRANULARITY
(anteriormente apenas para mover a posição do cursor) e adicionando o argumento ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
.
Em seguida, é possível recortar ou copiar com ACTION_CUT
, ACTION_COPY
e depois colar com
ACTION_PASTE
.
Observação:essas novas APIs também estão disponíveis para versões anteriores
do Android na Biblioteca de Suporte
do Android, com a classe
AccessibilityNodeInfoCompat
.
Declarar recursos de acessibilidade
A partir do Android 4.3, um serviço de acessibilidade precisa declarar recursos de acessibilidade
no arquivo de metadados para usar determinados recursos. Se a capacidade não for
solicitada no arquivo de metadados, o recurso será um ambiente autônomo. Para declarar os recursos
de acessibilidade do seu serviço, use atributos XML que correspondam às diversas
constantes de "capacidade" na classe
AccessibilityServiceInfo
.
Por exemplo, se um serviço não solicitar o recurso flagRequestFilterKeyEvents
,
ele não receberá eventos de teclas.
Teste e depuração
Testes automatizados da interface
A nova classe UiAutomation
fornece APIs que permitem simular ações
do usuário para automação de teste. Usando as APIs AccessibilityService
da plataforma, as APIs UiAutomation
permitem inspecionar o conteúdo da tela e injetar eventos arbitrários de teclado e toque.
Para acessar uma instância de UiAutomation
, chame Instrumentation.getUiAutomation()
. Para que isso funcione, é necessário fornecer a opção -w
com o comando instrument
ao executar InstrumentationTestCase
de adb shell
.
Com a instância UiAutomation
, é possível executar eventos arbitrários para testar
seu app chamando executeAndWaitForEvent()
, transmitindo um Runnable
para execução, um tempo limite
para a operação e uma implementação da interface UiAutomation.AccessibilityEventFilter
. É na implementação de UiAutomation.AccessibilityEventFilter
que você vai receber uma chamada
que permite filtrar os eventos em que tem interesse e determinar o sucesso ou
o fracasso de um determinado caso de teste.
Para observar todos os eventos durante um teste, crie uma implementação de UiAutomation.OnAccessibilityEventListener
e transmita-a para setOnAccessibilityEventListener()
.
A interface do listener recebe uma chamada para onAccessibilityEvent()
sempre que ocorre um evento, recebendo um objeto AccessibilityEvent
que descreve o evento.
Há várias outras operações que as APIs UiAutomation
expõem
em um nível muito baixo para incentivar o desenvolvimento de ferramentas de teste de interface, como uiautomator. Por exemplo,
UiAutomation
também pode:
- Injetar eventos de entrada
- Mudar a orientação da tela
- Fazer capturas de tela
E o mais importante para as ferramentas de teste de interface, as APIs UiAutomation
funcionam
além dos limites do aplicativo, ao contrário de Instrumentation
.
Eventos do Systrace para apps
O Android 4.3 adiciona a classe Trace
com dois métodos estáticos,
beginSection()
e endSection()
,
que permitem definir blocos de código a serem incluídos no relatório do Systrace. Ao criar
seções de código rastreável no app, os registros do Systrace fornecem uma análise muito mais detalhada
sobre onde ocorre a lentidão no app.
Para mais informações sobre como usar a ferramenta Systrace, leia Como analisar a exibição e o desempenho com o Systrace.
Segurança
Armazenamento de chaves do Android para chaves privadas de apps
O Android agora oferece um provedor de segurança Java personalizado na instalação KeyStore
, chamado Android Key Store, que permite gerar e salvar chaves privadas que
podem ser vistas e usadas apenas pelo seu app. Para carregar a Android Key Store, transmita
"AndroidKeyStore"
para KeyStore.getInstance()
.
Para gerenciar as credenciais particulares do app no Android Key Store, gere uma nova chave com
KeyPairGenerator
com KeyPairGeneratorSpec
. Primeiro,
receba uma instância de KeyPairGenerator
chamando getInstance()
. Em seguida, chame
initialize()
, transmitindo uma instância de
KeyPairGeneratorSpec
, que pode ser recebida usando
KeyPairGeneratorSpec.Builder
.
Por fim, para receber o KeyPair
, chame generateKeyPair()
.
Armazenamento de credenciais de hardware
O Android agora também oferece suporte ao armazenamento com suporte de hardware para suas credenciais KeyChain
,
proporcionando mais segurança, tornando as chaves indisponíveis para extração. Ou seja, quando
as chaves estão em um armazenamento de chaves protegido por hardware (Elemento de segurança, TPM ou TrustZone), elas podem ser usadas para
operações criptográficas, mas o material da chave privada não pode ser exportado. Nem mesmo o kernel do SO
não pode acessar esse material de chave. Embora nem todos os dispositivos Android ofereçam suporte ao armazenamento no
hardware, é possível verificar no momento da execução se o armazenamento protegido por hardware está disponível chamando
KeyChain.IsBoundKeyAlgorithm()
.
Declarações do manifesto
Recursos necessários declaráveis
Os valores a seguir agora têm suporte no elemento <uses-feature>
para que você possa garantir que seu app seja instalado somente em dispositivos que forneçam os recursos
necessários.
FEATURE_APP_WIDGETS
- Declara que o app oferece um widget de app e precisa ser instalado somente em dispositivos que
incluem uma tela inicial ou um local semelhante em que os usuários podem incorporar widgets de app.
Exemplo:
<uses-feature android:name="android.software.app_widgets" android:required="true" />
FEATURE_HOME_SCREEN
- Declara que o app se comporta como uma substituição da tela inicial e precisa ser instalado somente em
dispositivos com suporte a apps de tela inicial de terceiros.
Exemplo:
<uses-feature android:name="android.software.home_screen" android:required="true" />
FEATURE_INPUT_METHODS
- Declara que o app fornece um método de entrada personalizado (um teclado criado com
InputMethodService
) e precisa ser instalado somente em dispositivos com suporte a métodos de entrada de terceiros. Exemplo:<uses-feature android:name="android.software.input_methods" android:required="true" />
FEATURE_BLUETOOTH_LE
- Declara que o app usa APIs Bluetooth Low Energy e precisa ser instalado somente em dispositivos
capazes de se comunicar com outros dispositivos por Bluetooth Low Energy.
Exemplo:
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
Permissões do usuário
Os valores a seguir agora têm suporte em <uses-permission>
para declarar as
permissões que seu app exige para acessar determinadas APIs.
BIND_NOTIFICATION_LISTENER_SERVICE
- Obrigatórios para usar as novas APIs
NotificationListenerService
. SEND_RESPOND_VIA_MESSAGE
- Obrigatório para receber a intent
ACTION_RESPOND_VIA_MESSAGE
.
Para ter uma visão detalhada de todas as mudanças da API no Android 4.3, consulte o Relatório de diferenças da API.