API de nível: 18
Android 4.3 (JELLY_BEAN_MR2
)
é uma atualização da versão Jelly Bean que oferece novos recursos para usuários e apps
desenvolvedores de aplicativos. Este documento fornece uma introdução aos principais
novas APIs.
Como desenvolvedor de aplicativos, você deve fazer o download da imagem do sistema do Android 4.3 e da plataforma do SDK no SDK Manager assim que possível. 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 apps na plataforma do Android 4.3 para começar a usar as APIs mais recentes.
Atualização do nível da API
Para otimizar seu aplicativo para dispositivos com o Android 4.3,
defina o targetSdkVersion
como
"18"
, instale em uma imagem do sistema Android 4.3,
testá-lo e publicar uma atualização com essa alteração.
É possível usar APIs no Android 4.3 e, ao mesmo tempo, oferecer compatibilidade com versões anteriores adicionando
ao código que verificam o nível da API do sistema antes da execução
APIs não compatíveis com seu 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, permitindo a implementação de novos recursos em versões mais antigas da plataforma.
Para saber mais sobre como os níveis de API funcionam, leia O que é o nível da API?
Mudanças de comportamento importantes
Caso tenha publicado um aplicativo para Android anteriormente, saiba que ele pode ser afetado pelas mudanças no Android 4.3.
Se o app usa intents implícitas...
O app pode apresentar um comportamento incorreto em um ambiente de perfil restrito.
Os usuários em um ambiente de perfil restrito podem não
têm todos os apps Android padrão disponíveis. Por exemplo, um perfil restrito pode ter o
navegador da Web e o app de câmera desativados. Portanto, o 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 a Intent
,
o app poderá falhar em um perfil restrito.
Ao usar uma intent implícita, sempre verifique se um app está disponível para processar a intent chamando resolveActivity()
ou queryIntentActivities()
. 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 uma Account
, ele poderá falhar ou se comportar
inesperadamente quando usado em um perfil restrito.
Se você quiser impedir que perfis restritos usem seu app totalmente porque seu
app depende de informações sensíveis da conta, especifique o atributo android:requiredAccountType
no <application>
do manifesto
.
Se você quiser permitir que perfis restritos continuem usando seu app mesmo que eles não possam criar as próprias contas, e você poderá desativar os recursos do aplicativo que exigem uma conta ou permitir que 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 a VideoView...
Seu vídeo pode aparecer menor no Android 4.3.
Em versões anteriores do Android, o widget VideoView
estava incorreto
calculou o valor de "wrap_content"
para layout_height
e layout_width
para ser igual a "match_parent"
. Portanto, embora o uso de "wrap_content"
para a altura ou largura tenha fornecido o layout de vídeo desejado anteriormente,
Isso pode resultar em um vídeo muito menor no Android 4.3 e em versões mais recentes. Para corrigir o problema, substitua
"wrap_content"
por "match_parent"
e verifique se o vídeo aparece como esperado no
Android 4.3 e em versões mais antigas.
Perfis restritos
Em tablets Android, os usuários agora 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 são disponíveis para o perfil. Um novo conjunto de APIs no Android 4.3 também permite desenvolver as configurações de restrição para os apps que você desenvolve. Por exemplo, usando as novas APIs, é possível permitir que os usuários controlem o tipo de conteúdo disponível no app quando ele é executado em um ambiente de perfil restrito.
A interface para que os usuários controlem as restrições que você criou é gerenciada pelo
Aplicativo de configurações. Para que as configurações de restrição do app apareçam para o usuário, faça o seguinte:
é necessário declarar as restrições fornecidas pelo app criando uma BroadcastReceiver
que recebe a intent ACTION_GET_RESTRICTION_ENTRIES
. O sistema invoca essa intent para consultar
todos os apps para as restrições disponíveis e, em seguida, cria a interface para permitir que o usuário principal
gerenciar restrições para cada perfil restrito.
No método onReceive()
de
seu BroadcastReceiver
, você precisa criar um RestrictionEntry
para cada restrição fornecida pelo app. Cada RestrictionEntry
define um título de restrição, uma descrição e uma das
seguintes tipos de dados:
TYPE_BOOLEAN
para uma restrição que seja verdadeira ou falsa.TYPE_CHOICE
para uma restrição com várias opções mutuamente exclusivas (botões de opção).TYPE_MULTI_SELECT
para uma restrição que tem várias opções que não são mutuamente exclusivas (opções de caixa de seleção).
Em seguida, coloque todos os objetos RestrictionEntry
em um ArrayList
e coloque-o no resultado do broadcast receiver como o valor do
extra EXTRA_RESTRICTIONS_LIST
.
O sistema cria a interface para as restrições do seu app no app Configurações e salva cada uma delas.
restrição com a chave exclusiva que você forneceu para cada RestrictionEntry
objeto. Quando o usuário abrir seu app, você poderá consultar as restrições atuais
chamando getApplicationRestrictions()
.
Isso retorna um Bundle
contendo os pares de chave-valor para cada restrição.
definidos com os objetos RestrictionEntry
.
Se você deseja fornecer restrições mais específicas que não podem ser tratadas por booleanos, uma única
escolha e valores de múltipla escolha, você pode criar uma atividade em que o usuário pode especificar
e permitem que os usuários 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
que indique 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, seu
atividade deve, então, 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ê especificou
objetos RestrictionEntry
ou pares de chave-valor, respectivamente.
Suporte a contas em um perfil restrito
Qualquer conta adicionada ao usuário principal está disponível para um perfil restrito, mas o
não podem ser acessadas pelas 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 o seguinte
três opções:
Para ter acesso a uma conta de um perfil restrito, adicione o atributo android:restrictedAccountType
à tag <application>:
<application ... android:restrictedAccountType="com.example.account.type" >
Atenção: ativar esse atributo dá ao app acesso às contas do usuário principal de perfis restritos. Portanto, permita isso somente se as informações exibidas pelo app não revelarem informações de identificação pessoal (PII) consideradas sensíveis. As configurações do sistema vão informar ao usuário que o app concede perfis restritos às contas dele, então isso precisa ficar claro para ele. que o acesso à conta seja importante para a funcionalidade do seu app. Se possível, você também deve Fornecer controles de restrição adequados para o usuário principal que definam o nível de acesso à conta é permitido no seu app.
Se você quiser usar contas, mas não precisar delas para a funcionalidade
principal do app, verifique a disponibilidade de contas 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.
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:nessa situação, você não deve declarar novos atributos no arquivo de manifesto.
Se for importante que o app não esteja disponível para perfis restritos porque
seu app depende das informações pessoais sensíveis da conta e porque perfis restritos
no momento não é possível adicionar novas contas), adicione
O atributo android:requiredAccountType
para a tag <application>:
<application ... android:requiredAccountType="com.example.account.type" >
Por exemplo, o aplicativo Gmail usa esse atributo para desativar-se em perfis restritos, porque o e-mail pessoal do proprietário não deve estar disponível para perfis restritos.
Redes sem fio e conectividade
Bluetooth de baixa energia (Smart Ready)
O Android agora oferece suporte ao Bluetooth Low Energy (LE) com novas APIs no android.bluetooth
.
Com as novas APIs, você pode criar apps Android que se comunicam com Bluetooth de baixa energia
periféricos 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
dispositivos Android, declare um arquivo de manifesto como <uses-feature>
.
para "android.hardware.bluetooth_le"
:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
Se você já conhece as APIs clássicas de Bluetooth do Android, observe que usar o
As APIs Bluetooth LE têm algumas diferenças. O mais importante é que agora há uma classe BluetoothManager
que você precisa usar para algumas operações de alto nível,
como adquirir um BluetoothAdapter
, receber uma lista de dispositivos conectados
e verificar o estado de um dispositivo. Por exemplo, veja como acessar
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 Bluetooth
detecta um periférico Bluetooth LE, a implementação do BluetoothAdapter.LeScanCallback
recebe uma chamada para o
onLeScan()
. Isso
fornece um objeto BluetoothDevice
que representa a
dispositivo detectado, o valor RSSI do dispositivo e uma matriz de bytes contendo o código
registro de anúncio.
Se você quiser procurar apenas tipos específicos de periféricos, chame startLeScan()
e inclua uma matriz de objetos UUID
que especificam os serviços GATT compatíveis com seu app.
Observação: só é possível verificar dispositivos Bluetooth LE ou dispositivos Bluetooth clássico usando APIs anteriores. Não é possível procurar LE e Classic ao mesmo tempo dispositivos Bluetooth 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 a onConnectionStateChange()
para que você possa começar a se comunicar com o dispositivo se o método transmitir STATE_CONNECTED
como o novo estado.
O acesso a recursos de Bluetooth em um dispositivo também exige que o app solicite determinadas permissões do usuário do Bluetooth. Para mais informações, consulte o guia da API Bluetooth de baixa energia.
Modo somente busca por Wi-Fi
Ao tentar identificar a localização do usuário, o Android pode usar o Wi-Fi para determinar localização verificando os pontos de acesso próximos. No entanto, os usuários geralmente mantêm o Wi-Fi desativado para economizar bateria, resultando em dados de localização menos precisos. O Android agora inclui um modo de somente busca que permite que o Wi-Fi do dispositivo faça a varredura de pontos de acesso para ajudar a obter a localização sem se conectar a um ponto de acesso, reduzindo bastante o uso da bateria.
Se você quiser adquirir a localização do usuário, mas o Wi-Fi estiver desativado, peça para o
usuário ativar o modo de somente busca de Wi-Fi chamando startActivity()
com a ação ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
.
Configuração de Wi-Fi
As novas APIs WifiEnterpriseConfig
permitem que serviços voltados para empresas
automatizar 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 com uma mensagem de texto imediata sem precisar atender a chamada ou desbloquear o dispositivo.
Até agora, essas mensagens rápidas eram sempre processadas pelo aplicativo de mensagens padrão. Agora qualquer app
pode declarar a capacidade de processar essas mensagens criando um Service
.
com um filtro de intent para ACTION_RESPOND_VIA_MESSAGE
.
Quando o usuário responde a uma chamada com uma resposta rápida, o app Telefone envia
a intent ACTION_RESPOND_VIA_MESSAGE
com um URI
descrevendo o destinatário (o autor da chamada) e o extra EXTRA_TEXT
com a mensagem que o usuário quer enviar. Quando o serviço recebe a intent, ele deve entregar
a mensagem e parar imediatamente (seu app não deve mostrar uma atividade).
Para receber essa intent, é necessário declarar a permissão SEND_RESPOND_VIA_MESSAGE
.
Multimídia
Melhorias no MediaExtractor e no MediaCodec
Agora, o Android facilita a criação de players de streaming dinâmico
adaptativo por HTTP (DASH) de acordo com o padrão ISO/IEC 23009-1,
usando APIs existentes em MediaCodec
e MediaExtractor
. O framework subjacente a essas APIs foi atualizado para oferecer suporte
análise de arquivos MP4 fragmentados, mas seu app ainda é responsável pela análise dos metadados de MPD
e transmitindo 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 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
a esse esquema.
DRM de mídia
A nova classe MediaDrm
oferece uma solução modular para o gerenciamento de direitos
digitais (DRM) com seu conteúdo de mídia, separando as preocupações de DRM da reprodução de mídia. Para
essa separação de API permite que você reproduza conteúdo criptografado pelo Widevine sem ter que
usar o formato de mídia Widevine. Essa solução de DRM também oferece suporte à criptografia comum DASH para que você
pode usar vários esquemas de DRM com 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ça. 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
devem 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 lidar com conteúdo criptografado e MediaExtractor
para extrair e aplicar o multiplexador do seu conteúdo.
Primeiro, você precisa construir MediaExtractor
e
objetos MediaCodec
. É possível acessar o arquivo de identificação
UUID
, normalmente de metadados no conteúdo, e usados para criar um
instância de um objeto MediaDrm
com o construtor.
Codificação de vídeo de uma Surface
O Android 4.1 (nível 16 da API) adicionou a classe MediaCodec
para codificação
e decodificação de baixo nível do 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 uma Surface
como entrada para um codificador. Por exemplo, isso permite codificar a entrada
de um arquivo de vídeo existente ou usando frames gerados pelo OpenGL ES.
Para usar um Surface
como entrada para o codificador, primeiro chame configure()
para o MediaCodec
.
Em seguida, chame createInputSurface()
para receber o Surface
em que é possível transmitir a mídia.
Por exemplo, é possível usar o Surface
fornecido como a janela de um contexto
OpenGL transmitindo-o para eglCreateWindowSurface()
. Em seguida, ao renderizar a superfície, chame eglSwapBuffers()
para transmitir o frame ao MediaCodec
.
Para iniciar a codificação, chame start()
no MediaCodec
. Quando terminar, chame signalEndOfInputStream()
para encerrar a codificação e chame release()
no
Surface
.
Muxing 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 contraparte da MediaExtractor
adicionada no Android 4.2 para desmultiplexação (demuxing) de mídia.
Os formatos de saída compatíveis são definidos em MediaMuxer.OutputFormat
. Atualmente,
o 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.
O MediaMuxer
foi desenvolvido principalmente para funcionar com o MediaCodec
para processar o vídeo usando MediaCodec
e salvar o
a saída de um arquivo MP4 pelo MediaMuxer
. Você também pode usar MediaMuxer
em combinação com MediaExtractor
para realizar
a edição de mídia sem precisar codificar ou decodificar.
Progresso da reprodução e arraste do marcador de mídia para RemoteControlClient
No Android 4.0 (nível 14 da API), o RemoteControlClient
foi adicionado para
ativar os 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 permite que esses controles mostrem a posição
de reprodução e os controles para avançar rapidamente a reprodução. Se você tiver ativado o controle remoto para seu
app de mídia com as APIs RemoteControlClient
, será possível permitir a reprodução
de áudios com a implementação de duas novas interfaces.
Primeiro, é preciso ativar a sinalização FLAG_KEY_MEDIA_POSITION_UPDATE
transmitindo-a para
setTransportControlsFlags()
.
Em seguida, implemente as duas novas interfaces a seguir:
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 avança a reprodução com a interface do controle remoto.Depois de atualizar a reprodução com a nova posição, chame
setPlaybackState()
para indicar a novo estado, posição e velocidade da reprodução.
Com essas interfaces definidas, é possível defini-las para o RemoteControlClient
chamando setOnGetPlaybackPositionListener()
e
setPlaybackPositionUpdateListener()
, respectivamente.
Gráficos
Suporte ao OpenGL ES 3.0
O Android 4.3 adiciona interfaces Java e suporte nativo para OpenGL ES 3.0. As principais novas funcionalidades oferecidas 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 ponto flutuante de 32 bits e inteiro
- Renderização de textura avançada
- Padronização mais ampla do tamanho da textura e formatos do 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-o no arquivo de manifesto com a
<uses-feature>
e o atributo android:glEsVersion
. Exemplo:
<manifest> <uses-feature android:glEsVersion="0x00030000" /> ... </manifest>
E 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, incluindo como verificar a versão do OpenGL ES compatível do dispositivo no tempo de execução, consulte o guia da API OpenGL ES.
Mipmapping para drawables
Usar um mipmap como fonte do 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 no Bitmap
classe: o Android troca as imagens mip na sua Bitmap
quando você
forneceu uma origem de mipmap e ativou setHasMipMap()
. Agora, no Android 4.3, você também pode 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 a
um View
em que você pode adicionar conteúdo visual e que não afeta
da hierarquia de layouts. Você pode receber um ViewOverlay
para qualquer View
chamando getOverlay()
. A sobreposição
sempre tem o mesmo tamanho e posição da visualização de host (a visualização em que ela foi criada),
permitindo que você adicione conteúdo que aparece na frente da visualização de host, mas que não pode estender
os limites dela.
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 da visualização. No entanto, como a área utilizável de uma sobreposição é
restringida à mesma área da visualização do host, se você quiser animar uma visualização que se move 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
,
é possível 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
. O
A classe ViewGroupOverlay
é uma subclasse.
de ViewOverlay
, que também permite adicionar View
objetos 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 principal e 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 com limites ópticos
Para visualizações que contêm imagens de plano de fundo Nine-Patch, agora você pode especificar que elas precisam fiquem alinhadas com as visualizações vizinhas com base no limites da imagem de plano de fundo, que o "clipe" limites 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 clipe (o comportamento padrão), enquanto a figura 2 está usando limites ópticos. Como o As imagens Nine-Patch usadas para o botão e o Porta-retratos incluem padding nas extremidades, eles parecem não se alinhar entre si ou com o texto ao usar limites de corte.
Observação: as capturas de tela nas figuras 1 e 2 têm a opção limites de layout" de desenvolvedor ativada. Para cada visualização, as linhas vermelhas indicam os limites ópticos, as linhas azuis indicam os limites do clipe e as linhas rosa indicam as margens.

Figura 1. Layout que usa limites de corte (padrão).

Figura 2. Layout usando limites ópticos.
Para alinhar as visualizações com base nos limites ópticos, defina o atributo android:layoutMode
como "opticalBounds"
em um dos layouts pai. Exemplo:
<LinearLayout android:layoutMode="opticalBounds" ... >

Figura 3. Visualização ampliada do botão Nine-Patch do Holo com limites ópticos.
Para que isso funcione, as imagens nine-patch aplicadas ao plano de fundo das visualizações precisam especificar os limites ópticos usando linhas vermelhas na parte de baixo e à direita do arquivo nine-patch (como mostrado na Figura 3). As linhas vermelhas indicam a região que deve ser subtraída da os limites de corte, deixando os limites ópticos da imagem.
Quando você ativa os limites ópticos para uma ViewGroup
no layout, todos
as visualizações descendentes herdam o modo de layout dos limites ópticos, a menos que você o modifique para um grupo
definindo android:layoutMode
como "clipBounds"
. Todos os elementos de layout também respeitam
limites ópticos das visualizações filhas, adaptando os próprios limites com base nos limites ópticos da
as visualizações dentro deles. No entanto, os elementos de layout (subclasses de ViewGroup
)
atualmente não oferecem suporte a limites ópticos para imagens de nove retângulos aplicadas ao próprio plano de fundo.
Se você criar uma visualização personalizada criando uma subclasse de View
, ViewGroup
ou qualquer subclasse, a visualização vai herdar esses comportamentos de vinculação óptica.
Observação: todos os widgets com suporte do tema Holo foram atualizados
com limites ópticos, incluindo Button
, Spinner
,
EditText
e outros. Para aproveitar os benefícios imediatamente, defina 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 imagens Nine-Patch com a ferramenta Draw 9-patch, mantenha a tecla Control pressionada quando clicando nos pixels da borda.
Animação para valores de retângulo
Agora você pode animar entre dois valores Rect
com o novo RectEvaluator
. Essa nova classe é uma implementação de TypeEvaluator
que pode ser transmitida para ValueAnimator.setEvaluator()
.
Anexar janela e focar o listener
Anteriormente, se você quisesse detectar quando a visualização fosse anexada/desanexada à janela ou
quando o foco dela mudasse, 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()
.
E, 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 seu app preencha toda a tela de todas as TVs, ative o overscan
para o layout do seu app. O modo de overscan é determinado pela sinalização FLAG_LAYOUT_IN_OVERSCAN
, que pode ser ativada com temas de plataforma como
Theme_DeviceDefault_NoActionBar_Overscan
ou ativando o
windowOverscan
em um tema personalizado.
Orientação da tela
O atributo screenOrientation
da tag <activity>
agora aceita outros valores para respeitar a preferência do usuário de rotação automática:
"userLandscape"
- Tem o mesmo comportamento de
"sensorLandscape"
, exceto se o usuário desativar a rotação automática. Nesse caso, ele será bloqueado na orientação normal de paisagem e não será invertido. "userPortrait"
- Tem o mesmo comportamento de
"sensorPortrait"
, exceto se o usuário desativar a rotação automática. Nesse caso, ele será bloqueado na orientação normal de retrato e não será invertido. "fullUser"
- Tem o mesmo comportamento de
"fullSensor"
e permite a rotação nas quatro direções, exceto se o usuário desativar a rotação automática, que será bloqueada 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 alternar as orientações da tela. As três animações são:
Observação: essas animações só estão disponíveis se você tiver definido a atividade para usar o modo "tela cheia", que pode ser ativado com temas como Theme.Holo.NoActionBar.Fullscreen
.
Por exemplo, veja como ativar o "crossfade" animação:
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 é baseado no norte magnético.
Os novos sensores TYPE_GYROSCOPE_UNCALIBRATED
e TYPE_MAGNETIC_FIELD_UNCALIBRATED
fornecem dados brutos do sensor sem
consideração para estimativas de viés. Ou seja, os sensores TYPE_GYROSCOPE
e TYPE_MAGNETIC_FIELD
fornecem dados que consideram a distorção estimada da deriva da 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 oferecem os valores de viés estimados separadamente. Esses sensores permitem
forneça sua própria 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 app receba informações sobre novas notificações à medida que são postadas pelo sistema.
Se o app usa as APIs do serviço de acessibilidade para acessar as notificações do sistema, atualize-o para usar essas APIs.
Provedor de contatos
Consultar "contactables"
A nova consulta do Provedor de contatos, Contactables.CONTENT_URI
, fornece uma maneira eficiente de obter uma Cursor
que contenha todos os endereços de e-mail e números de telefone pertencentes a todos os contatos que correspondam à consulta especificada.
Consultar deltas de contatos
Novas APIs foram adicionadas ao Provedor de contatos para permitir que você consulte de forma eficiente as alterações recentes nos dados de contatos. Antes, o app podia ser notificado quando algo nos dados de contatos mudava, mas você não saberia exatamente o que mudou e precisaria recuperar todos os contatos e então acessar cada um deles para descobrir a mudança.
Para acompanhar as alterações 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 rastrear 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 um tempo limitado. Assim como no método CONTACT_LAST_UPDATED_TIMESTAMP
, é possível usar o novo parâmetro de seleção, CONTACT_DELETED_TIMESTAMP
, para verificar 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, recria o
banco de dados do Provedor de contatos. O objetivo é sinalizar aos apps que eles precisam descartar todas as informações de contato
armazenadas e recarregar com uma nova consulta.
Para conferir um exemplo de código que usa essas APIs para verificar mudanças nos contatos, consulte o exemplo ApiDemos disponível no download SDK Samples.
Localização
Compatibilidade aprimorada com texto bidirecional
As versões anteriores do Android são compatíveis com idiomas e layout da direita para a esquerda (RTL).
mas às vezes não lidam corretamente com texto de 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 distorcer 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 você 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 hebraico, a string formatada será exibida assim:
האם התכוונת ל 15 Bay Street, Laurel, CA?
Está errado, porque "15" deve ser a esquerda da "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 heurística de estimativa de direcionalidade de primeira forte, que pode dar errado se o primeiro
indicador de direção do texto não representar a direção adequada 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 por meio do Suporte do Android
Biblioteca, com a classe BidiFormatter
e APIs relacionadas.
Serviços de acessibilidade
Gerenciar eventos de teclas
Agora, uma AccessibilityService
pode receber um callback para
eventos de entrada de tecla com o método de callback onKeyEvent()
. Isso permite que seu serviço de acessibilidade processe a entrada de
dispositivos de entrada baseados em teclas, como um teclado, e traduza esses eventos em ações especiais que
antes só eram possíveis com entrada por toque ou o botão direcional do dispositivo.
Selecionar texto e copiar/colar
O AccessibilityNodeInfo
agora fornece APIs que permitem
uma AccessibilityService
para selecionar, recortar, copiar e colar
em um nó.
Para especificar a seleção de texto a ser cortado ou copiado, o serviço de acessibilidade pode usar a nova
ação, ACTION_SET_SELECTION
, transmitindo
a posição inicial e final da seleção com ACTION_ARGUMENT_SELECTION_START_INT
e ACTION_ARGUMENT_SELECTION_END_INT
.
Como alternativa, você pode selecionar texto manipulando a posição do cursor usando a ação
atual, ACTION_NEXT_AT_MOVEMENT_GRANULARITY
,
(anteriormente apenas para mover a posição do cursor) e adicionando o argumento ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
.
Você pode 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 pela 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 os recursos de acessibilidade
no arquivo de metadados para usar determinados recursos de acessibilidade. Se o capability não for
solicitado no arquivo de metadados, o recurso não será executado. Para declarar os capabilities
de acessibilidade do serviço, use atributos XML que correspondam às várias
constantes "capability" na classe
AccessibilityServiceInfo
.
Por exemplo, se um serviço não solicitar o recurso flagRequestFilterKeyEvents
,
ele não receberá eventos principais.
Teste e depuração
Testes automatizados da interface
A nova classe UiAutomation
oferece APIs que permitem simular ações
do usuário para automação de testes. Ao usar 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
Para que isso funcione, é necessário fornecer a opção -w
com o comando instrument
.
ao executar InstrumentationTestCase
no adb shell
.
Com a instância UiAutomation
, é possível executar eventos arbitrários para testar
seu app chamando executeAndWaitForEvent()
, transmitindo um Runnable
para ele executar, um tempo limite
para a operação e uma implementação da interface UiAutomation.AccessibilityEventFilter
. Você vai receber uma chamada na implementação do UiAutomation.AccessibilityEventFilter
.
que permite filtrar os eventos do seu interesse e determinar o sucesso ou
a falha 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, receber um objeto AccessibilityEvent
que descreve o evento.
As APIs UiAutomation
expõem várias outras operações
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 ferramentas de teste de interface, as APIs UiAutomation
funcionam
entre os limites do aplicativo, ao contrário dos 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 com o relatório do Systrace. Ao criar
seções de código rastreáveis no seu aplicativo, os registros do Systrace fornecem uma abordagem
análise de onde ocorre a lentidão no aplicativo.
Para saber mais sobre como usar a ferramenta Systrace, leia Análise de tela e desempenho com o Systrace.
Segurança
Repositório de chaves privadas do Android para apps
O Android agora oferece um provedor de segurança Java personalizado na
facilidade KeyStore
, chamado Android Key Store, que permite gerar e salvar chaves privadas que
podem ser vistas e usadas apenas pelo seu app. Para carregar o Android Key Store, transmita
"AndroidKeyStore"
para KeyStore.getInstance()
.
Para gerenciar as credenciais privadas do app na loja de chaves do Android, 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 obtida usando
KeyPairGeneratorSpec.Builder
.
Por fim, acesse KeyPair
chamando generateKeyPair()
.
Armazenamento de credenciais de hardware
O Android também oferece suporte a armazenamento com suporte de hardware para suas credenciais KeyChain
,
oferecendo mais segurança ao deixar as chaves indisponíveis para extração. Ou seja, uma vez
estão em um repositório de chaves protegido por hardware (Secure Element, TPM ou TrustZone), elas podem ser usadas para
operações criptográficas, mas não é possível exportar o material da chave privada. Até mesmo o kernel do SO
não pode acessar o material da chave. Embora nem todos os dispositivos Android ofereçam suporte ao armazenamento em
hardware, você pode verificar no momento da execução se o armazenamento com suporte a hardware está disponível chamando
KeyChain.IsBoundKeyAlgorithm()
.
Declarações do manifesto
Recursos necessários declaráveis
Os valores a seguir agora são compatíveis com o elemento <uses-feature>
,
de forma que é possível garantir que o app seja instalado somente em dispositivos que ofereçam os recursos
necessários.
FEATURE_APP_WIDGETS
- Declara que o app fornece um widget e precisa ser instalado apenas em dispositivos que
incluem uma tela inicial ou local semelhante em que os usuários podem incorporar widgets.
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 só pode ser instalado em
compatíveis com 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 oferece um método de entrada personalizado (um teclado criado com
InputMethodService
) e precisa ser instalado apenas em dispositivos que ofereçam 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 de baixa energia e precisa ser instalado apenas em dispositivos
que podem se comunicar com outros dispositivos por Bluetooth de baixa energia.
Exemplo:
<uses-feature android:name="android.software.bluetooth_le" android:required="true" />
Permissões do usuário
Os valores a seguir agora são compatíveis com o <uses-permission>
para declarar as
permissões necessárias para que o app acesse determinadas APIs.
BIND_NOTIFICATION_LISTENER_SERVICE
- Obrigatório para usar as novas APIs
NotificationListenerService
. SEND_RESPOND_VIA_MESSAGE
- Necessário para receber o
ACTION_RESPOND_VIA_MESSAGE
intenção.
Para conferir uma visualização detalhada de todas as alterações de API no Android 4.3, consulte o Relatório de diferenças de API.