Android 4.3 APIs

API de nível: 18

O Android 4.3 (JELLY_BEAN_MR2) é uma atualização da versão Jelly Bean e 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, você precisa 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 seu app, use a imagem do sistema Android 4.3 para testar seu app no Android Emulator. Em seguida, crie seus apps 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 a targetSdkVersion como "18", instale-a 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 sem 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 é o 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 no Android 4.3.

Se o app usa 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 ter o navegador da Web e o app de câmera desativados. Portanto, seu app não deve 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, verifique sempre 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 de forma inesperada quando usado em um perfil restrito.

Se você quiser impedir que perfis restritos usem seu app inteiramente porque ele depende de informações confidenciais da conta, especifique o atributo android:requiredAccountType no elemento <application> do manifesto.

Para permitir que perfis restritos continuem usando o app, mesmo que não possam criar as próprias contas, desative os recursos do app que exigem uma conta ou permita que perfis restritos acessem as contas criadas pelo usuário principal. Para mais informações, consulte a seção abaixo sobre Como dar suporte a contas em um perfil restrito.

Se o app usa o VideoView...

É possível que seus vídeos pareçam menores no Android 4.3.

Nas versões anteriores do Android, o widget VideoView calculou incorretamente o valor "wrap_content" de layout_height e layout_width para ser igual a "match_parent". Portanto, embora o uso de "wrap_content" para a altura ou largura possa ter fornecido anteriormente o layout de vídeo desejado, 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 conforme o 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 estão disponíveis para o perfil. Um novo conjunto de APIs no Android 4.3 também permite criar configurações de restrição finais para os apps que você desenvolve. Por exemplo, com as novas APIs, é possível permitir que os usuários controlem o tipo de conteúdo disponível no app quando ele for executado em um ambiente de perfil restrito.

A IU 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 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 as restrições disponíveis em todos os apps e 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 um RestrictionEntry para cada restrição fornecida pelo app. Cada RestrictionEntry define um título, uma descrição e um dos tipos de dados abaixo:

  • TYPE_BOOLEAN para uma restrição que é verdadeira ou falsa.
  • TYPE_CHOICE para uma restrição que tem várias opções mutuamente exclusivas (opções de botão 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 uma ArrayList e coloque-a 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 o 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.

Para fornecer restrições mais específicas que não podem 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 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, indicando a classe Activity para iniciar. 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.

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 pelas APIs AccountManager por padrão. Se você tentar adicionar uma conta com AccountManager enquanto estiver em um perfil restrito, receberá um resultado de falha. Devido a essas restrições, você tem três opções a seguir:

  • Permitir o acesso às contas do proprietário em um perfil restrito

    Para acessar uma conta em um perfil restrito, adicione o atributo android:restrictedAccountType à tag <application>:

    <application ...
        android:restrictedAccountType="com.example.account.type" >
    

    Cuidado:a ativação desse atributo fornece ao app acesso às contas do usuário principal em perfis restritos. Portanto, permita isso somente se as informações mostradas pelo app não revelam informações de identificação pessoal (PII) que são consideradas sensíveis. As configurações do sistema vão informar 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.

  • Desative algumas funcionalidades quando não for possível modificar contas.

    Se você quiser usar contas, mas não as exige para a funcionalidade principal do app, verifique a disponibilidade da conta e desative os recursos quando eles 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 DISALLOW_MODIFY_ACCOUNTS extra no resultado. Se for true, desative qualquer funcionalidade do app que exija acesso a 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 novos atributos no arquivo de manifesto.

  • Desative o app quando não for possível acessar contas particulares.

    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 não podem adicionar novas contas no momento, adicione o atributo android:requiredAccountType à tag <application>:

    <application ...
        android:requiredAccountType="com.example.account.type" >
    

    Por exemplo, o app Gmail usa esse atributo para desativar a si mesmo 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 Low Energy (LE) 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 pode 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 agora você pode acessar 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 publicidade 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 buscar dispositivos Bluetooth clássicos 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 do Bluetooth em um dispositivo também exige que seu 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 ajudar a 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, fazendo com que os dados de localização sejam 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 assim o uso da bateria.

    Se você quiser saber a localização do usuário, mas o Wi-Fi estiver desativado, solicite ao usuário que 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 voltados a empresas 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 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 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, é necessário declarar a permissão SEND_RESPOND_VIA_MESSAGE.

    Multimídia

    Melhorias no MediaExtractor e MediaCodec

    Com o uso de APIs existentes em MediaCodec e MediaExtractor, o Android agora facilita a criação de players próprios de streaming adaptável dinâmico por HTTP (DASH, na sigla em inglês) de acordo com o padrão ISO/IEC 23009-1. O framework subjacente dessas APIs foi atualizado para oferecer suporte à análise de arquivos MP4 fragmentados, mas o 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 gerenciamento de direitos digitais (DRM, na sigla em inglês) com seu conteúdo de mídia, separando as questões de DRM da reprodução de mídia. Por exemplo, essa separação de API permite que você reproduza 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 de solicitação de chave opacas e processar mensagens de chave-resposta 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 fornece apenas a capacidade de gerar e processar as mensagens.

    As APIs MediaDrm precisam ser usadas em conjunto com as APIs MediaCodec que foram 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 a multiplexação do conteúdo.

    Primeiro, construa os objetos MediaExtractor e MediaCodec. Em seguida, você pode acessar a UUID de identificação do esquema de DRM, geralmente a partir de metadados no conteúdo, e usá-la 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 a mídia com uma matriz ByteBuffer, mas o Android 4.3 agora permite usar um Surface como entrada para um codificador. Isso permite, por exemplo, que você codifique a entrada de um arquivo de vídeo existente ou use 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 você pode transmitir a 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 à MediaCodec.

    Para começar a codificação, chame start() na MediaCodec. Quando terminar, chame signalEndOfInputStream() para encerrar a codificação e release() no Surface.

    Multixing 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 contrapartida à classe MediaExtractor adicionada no Android 4.2 para a desmultiplexação (demuxing) de mídia.

    Os formatos de saída compatíveis são definidos em MediaMuxer.OutputFormat. Atualmente, MP4 é o único formato de saída compatível e MediaMuxer aceita apenas um stream de áudio e/ou 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 salvar a saída em um arquivo MP4 por meio de MediaMuxer. Também é possível usar MediaMuxer com MediaExtractor para editar mídia sem precisar codificar ou decodificar.

    Progresso da reprodução e refinamento para RemoteControlClient

    No Android 4.0 (API de nível 14), o RemoteControlClient foi adicionado para ativar controles de mídia a partir de clientes de controle remoto, como os controles disponíveis na tela de bloqueio. O Android 4.3 agora oferece a capacidade desses controles de exibir a posição de reprodução e os controles de acesso a todos os controles. Se você ativou o controle remoto para o app de música com as APIs RemoteControlClient, pode implementar duas novas interfaces para permitir a barra de progressão de reprodução.

    Primeiro, você precisa ativar a sinalização 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 aumenta o nível da 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 o 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 um 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 do tamanho da textura e dos 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-o 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 saber mais sobre como usar o OpenGL ES, inclusive como verificar a versão do OpenGL ES compatível com o dispositivo no momento da 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, o que pode ser útil principalmente se você espera que a imagem seja dimensionada durante uma animação.

    O Android 4.2 (nível 17 da API) adicionou suporte a mipmaps na classe Bitmap: o Android troca as imagens mip no Bitmap quando você fornece uma origem 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 receber 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 de que foi criada), permitindo que você adicione conteúdo que aparece na frente da visualização host, 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 movendo-se 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 uma 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. 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 abaixo 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 é possível 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 "recortar" da visualização.

    Por exemplo, as figuras 1 e 2 mostram o mesmo layout, mas a versão na Figura 1 usa 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 preenchimento 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 1 e 2, a configuração de desenvolvedor "Mostrar limites do layout" está ativada. Para cada visualização, linhas vermelhas indicam os limites ópticos, linhas azuis indicam os limites de corte e rosa indicam 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 pais. Por exemplo:

    <LinearLayout android:layoutMode="opticalBounds" ... >
    

    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 da parte inferior e do lado direito 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 criando subclasses de View, ViewGroup ou de qualquer subclasse, a visualização vai herdar esses comportamentos de vínculo óptico.

    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" caso seu app aplique 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 ao clicar nos pixels de 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 janelas

    Antes, se você quisesse detectar quando a 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 para o layout do app. O modo de 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 é compatível com outros valores para respeitar a preferência do usuário por rotação automática:

    "userLandscape"
    O comportamento é o mesmo que o "sensorLandscape", mas se o usuário desativar o giro automático, ele será bloqueado na orientação de paisagem normal e não será virado.
    "userPortrait"
    O comportamento é igual ao "sensorPortrait", mas se o usuário desativar o giro automático, ele será bloqueado na orientação de retrato normal e não será virado.
    "fullUser"
    O comportamento é igual ao "fullSensor" e permite a rotação em todas as quatro direções, exceto se o usuário desativar o giro automático, ele é 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 entre uma das três animações que você quer usar quando o sistema alternar a orientação da tela. As três animações são:

    Observação:essas animações só estarão disponíveis se você configurar a atividade para usar o modo "tela cheia", que pode ser ativada com temas como Theme.Holo.NoActionBar.Fullscreen.

    Por exemplo, veja como ativar a animação "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 sem consideração para estimativas de viés. Ou seja, os sensores TYPE_GYROSCOPE e TYPE_MAGNETIC_FIELD existentes fornecem dados que consideram o viés estimado de deslocamento do giroscópio e ferro duro no dispositivo, respectivamente. Já as novas versões "não calibradas" desses sensores fornecem os dados brutos e os valores de viés estimados separadamente. Esses sensores permitem que você forneça sua própria calibragem 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 seu aplicativo usa as APIs de serviço de acessibilidade para acessar notificações do sistema, você deve atualizá-lo para usar essas APIs.

    Provedor de contatos

    Consulta para "contactable"

    A nova consulta do Provedor de contatos, Contactables.CONTENT_URI, oferece uma maneira eficiente de receber um Cursor que contenha todos os endereços de e-mail e números de telefone pertencentes a todos os contatos que correspondam à consulta especificada.

    Consulta de deltas de contatos

    Novas APIs foram adicionadas ao Provedor de contatos, que permitem consultar com eficiência 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 havia sido alterado e precisaria recuperar todos os contatos e, em seguida, interagir com eles para descobrir a mudança.

    Para rastrear 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 consulta do 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 nesta 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 verificar quais contatos foram excluídos desde a última consulta do provedor. A tabela também contém a constante DAYS_KEPT_MILLISECONDS com 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 pelo menu de configurações do sistema, recriando o banco de dados do Provedor de contatos. O objetivo é sinalizar aos apps que eles precisam descartar todas as informações de contato que armazenaram e recarregá-las com uma nova consulta.

    Para ver um exemplo de código que usa 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), mas às vezes não processam corretamente textos em direção mista. Portanto, o Android 4.3 adiciona as APIs BidiFormatter, que ajudam a formatar corretamente o texto com conteúdo de direção oposta sem confundir nenhuma parte do texto.

    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" precisa ser deixado de "Bay Street". A solução é usar BidiFormatter e o método unicodeWrap(). Por exemplo, o código acima fica:

    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 direção do primeiro resultado, 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 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 tecla 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 antes eram possíveis 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, 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 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, 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 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 o recurso não for solicitado 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 várias constantes de "recurso" 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

    Teste automatizado de interface

    A nova classe UiAutomation fornece APIs que permitem simular ações do usuário para automatizar 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 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(), passando um Runnable para execução, um período de tempo limite para a operação e uma implementação da interface UiAutomation.AccessibilityEventFilter. Na implementação de UiAutomation.AccessibilityEventFilter, você vai receber uma chamada que permite filtrar os eventos do seu interesse e determinar o sucesso ou a falha de um 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 IU, 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 IU, as APIs UiAutomation funcionam em vários limites do aplicativo, ao contrário daquelas em 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 de onde ocorre a lentidão no app.

    Para saber mais 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 do app

    O Android agora oferece um provedor de segurança Java personalizado na instalação de 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 seu app na Android Key Store, gere uma nova chave usando 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, chame generateKeyPair() para receber o KeyPair.

    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 ao tornar 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 a armazenamento em hardware, é possível verificar no momento da execução se o armazenamento com suporte de 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 garantir que o app seja instalado apenas em dispositivos que tenham 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. Por exemplo:
    <uses-feature android:name="android.software.app_widgets" android:required="true" />
    
    FEATURE_HOME_SCREEN
    Declara que seu app se comporta como uma substituição da tela inicial e precisa ser instalado apenas em dispositivos com suporte a apps da tela inicial de terceiros. Por 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 apenas em dispositivos com suporte a métodos de entrada de terceiros. Por exemplo:
    <uses-feature android:name="android.software.input_methods" android:required="true" />
    
    FEATURE_BLUETOOTH_LE
    Declara que seu app usa APIs Bluetooth Low Energy e precisa ser instalado somente em dispositivos capazes de se comunicar com outros dispositivos via Bluetooth Low Energy. Por 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 o app exige para acessar determinadas APIs.

    BIND_NOTIFICATION_LISTENER_SERVICE
    Obrigatórias 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.