Android 4.3 APIs

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:

  • Permitir o acesso às contas do proprietário a partir de um perfil restrito

    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.

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

    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.

  • 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 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.

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

    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" ... >
    

    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.