Mostrar Activity De Chamada Com Tela Bloqueada No Android

by Axel Sørensen 58 views

E aí, pessoal! Tudo bem com vocês? Se você está desenvolvendo um app de vídeo e voz e precisa mostrar uma Activity de chamada mesmo quando o dispositivo Android está bloqueado e com a tela desligada, você veio ao lugar certo! Essa é uma situação comum em aplicativos de comunicação, e vamos explorar juntos como resolver esse desafio. Usando o Firebase Cloud Messaging (FCM) como ponto de partida, vamos mergulhar nas soluções e mostrar o passo a passo para você implementar essa funcionalidade de forma eficiente e elegante.

O Desafio de Exibir uma Activity com a Tela Bloqueada

Mostrar uma Activity de chamada com a tela bloqueada é um desafio interessante no desenvolvimento Android. Por padrão, o sistema operacional Android tem mecanismos de segurança que impedem que aplicativos iniciem Activities diretamente quando o dispositivo está bloqueado ou com a tela desligada. Isso é para evitar comportamentos indesejados e garantir a privacidade do usuário. No entanto, em apps de comunicação, como o seu de vídeo e voz, é crucial que a notificação de chamada seja exibida imediatamente, mesmo nessas condições.

Para contornar essa restrição, precisamos usar alguns recursos e técnicas específicas do Android. O objetivo é garantir que a Activity de chamada seja exibida assim que o usuário receber uma notificação de chamada, proporcionando uma experiência de usuário fluida e intuitiva. Vamos explorar as principais abordagens e os passos necessários para implementar essa funcionalidade no seu aplicativo.

Usando o Firebase Cloud Messaging (FCM)

O Firebase Cloud Messaging (FCM) é uma ferramenta poderosa para enviar notificações push para dispositivos Android. Se você já está utilizando o FCM no seu aplicativo, ótimo! Isso facilita bastante o processo. O FCM permite enviar mensagens para dispositivos específicos ou para grupos de dispositivos, o que é perfeito para notificações de chamadas.

A ideia é que, quando um usuário tenta ligar para outro, o servidor do seu aplicativo envie uma mensagem FCM para o dispositivo do destinatário. Essa mensagem irá conter informações sobre a chamada, como o ID do chamador, o tipo de chamada (vídeo ou voz) e outras informações relevantes. Ao receber essa mensagem, o aplicativo no dispositivo do destinatário irá exibir a Activity de chamada.

Configurando o FCM no seu Projeto

Se você ainda não configurou o FCM no seu projeto, não se preocupe! É um processo relativamente simples. Primeiro, você precisa criar um projeto no Firebase Console (https://console.firebase.google.com/) e adicionar seu aplicativo Android a esse projeto. O Firebase irá gerar um arquivo google-services.json que você precisa adicionar à pasta app/ do seu projeto Android.

Em seguida, adicione as dependências do FCM ao seu arquivo build.gradle (Module: app):

implementation 'com.google.firebase:firebase-messaging:23.0.0'

(Lembre-se de verificar a versão mais recente no site do Firebase e substituir 23.0.0 pela versão atual.)

Após adicionar as dependências, você precisa sincronizar o Gradle para que as bibliotecas sejam baixadas e adicionadas ao seu projeto. Com o FCM configurado, podemos passar para a próxima etapa: criar o serviço de recebimento de mensagens.

Criando um Serviço para Receber Mensagens FCM

Para receber mensagens FCM, você precisa criar um serviço (um Service do Android) que estenda a classe FirebaseMessagingService. Esse serviço será responsável por lidar com as mensagens recebidas do FCM. Crie uma nova classe no seu projeto, por exemplo, MyFirebaseMessagingService, e faça com que ela estenda FirebaseMessagingService:

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // Lógica para lidar com a mensagem recebida
    }

    @Override
    public void onNewToken(String token) {
        // Lógica para lidar com o novo token FCM
    }
}

O método onMessageReceived é chamado sempre que uma nova mensagem FCM é recebida. É aqui que você irá implementar a lógica para exibir a Activity de chamada. O método onNewToken é chamado quando um novo token FCM é gerado para o dispositivo. Você pode usar esse token para enviar mensagens direcionadas a dispositivos específicos.

Implementando a Lógica para Exibir a Activity de Chamada

Dentro do método onMessageReceived, você precisa extrair as informações da mensagem FCM e usar essas informações para exibir a Activity de chamada. Aqui está um exemplo de como você pode fazer isso:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    if (remoteMessage.getData().size() > 0) {
        String callerId = remoteMessage.getData().get("callerId");
        String callType = remoteMessage.getData().get("callType");

        // Lógica para exibir a Activity de chamada
        showCallActivity(callerId, callType);
    }
}

Neste exemplo, estamos extraindo o callerId e o callType da mensagem FCM. Esses são apenas exemplos, e você pode adicionar outros dados relevantes para a sua aplicação. Em seguida, chamamos o método showCallActivity para exibir a Activity de chamada. Vamos implementar esse método agora.

Exibindo a Activity de Chamada com a Tela Bloqueada

Para exibir a Activity de chamada mesmo com a tela bloqueada, precisamos usar algumas flags específicas na Intent que inicia a Activity. Aqui está um exemplo de como você pode implementar o método showCallActivity:

private void showCallActivity(String callerId, String callType) {
    Intent intent = new Intent(this, CallActivity.class);
    intent.putExtra("callerId", callerId);
    intent.putExtra("callType", callType);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
            Intent.FLAG_ACTIVITY_SINGLE_TOP |
            Intent.FLAG_ACTIVITY_CLEAR_TOP |
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
            WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "call_channel")
            .setSmallIcon(R.drawable.ic_call)
            .setContentTitle("Chamada Recebida")
            .setContentText("Chamada de " + callerId)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setCategory(NotificationCompat.CATEGORY_CALL)
            .setContentIntent(pendingIntent)
            .setAutoCancel(true) // Dismiss the notification when the user taps it
            .setFullScreenIntent(pendingIntent, true); // Show as heads-up notification

    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

    // Since android Oreo notification channel is needed.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel("call_channel",
                "Call Channel",
                NotificationManager.IMPORTANCE_HIGH);
        notificationManager.createNotificationChannel(channel);
    }

    notificationManager.notify(0, builder.build());
}

Vamos analisar o que está acontecendo neste código:

  1. Criamos uma Intent para a CallActivity e adicionamos as informações da chamada como extras.
  2. Adicionamos flags importantes à Intent:
    • Intent.FLAG_ACTIVITY_NEW_TASK: Inicia a Activity em uma nova tarefa.
    • Intent.FLAG_ACTIVITY_SINGLE_TOP: Se a Activity já estiver em execução no topo da pilha, ela não será reiniciada.
    • Intent.FLAG_ACTIVITY_CLEAR_TOP: Se a Activity já estiver em execução na pilha, todas as Activities acima dela serão removidas.
    • WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED: Permite que a Activity seja exibida mesmo com a tela bloqueada.
    • WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD: Dispensa o bloqueio de tela (se seguro) quando a Activity é exibida.
  3. Criamos um PendingIntent para iniciar a Activity quando a notificação for clicada.
  4. Criamos uma notificação usando NotificationCompat.Builder. Definimos o ícone, título, texto e prioridade da notificação. Também definimos a categoria como NotificationCompat.CATEGORY_CALL para que o sistema trate essa notificação como uma chamada.
  5. Usamos setFullScreenIntent para exibir a notificação como uma heads-up notification, que aparece no topo da tela mesmo quando o dispositivo está bloqueado.
  6. Criamos um NotificationChannel para dispositivos com Android Oreo (API nível 26) ou superior. Isso é necessário para exibir notificações corretamente nesses dispositivos.
  7. Finalmente, exibimos a notificação usando NotificationManagerCompat.notify.

Com esse código, a Activity de chamada será exibida assim que a notificação for recebida, mesmo com a tela bloqueada. O usuário poderá atender ou rejeitar a chamada diretamente da tela de bloqueio.

Registrando o Serviço no Manifest

Não se esqueça de registrar o serviço no seu arquivo AndroidManifest.xml:

<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

Certifique-se de que o atributo android:exported está definido como false, pois este serviço não precisa ser acessado por outros aplicativos. O filtro de intent com a action com.google.firebase.MESSAGING_EVENT indica que este serviço irá lidar com mensagens FCM.

Lidando com Permissões

Para exibir a Activity de chamada e usar os recursos do sistema, você pode precisar solicitar algumas permissões no seu aplicativo. As permissões mais comuns são:

  • android.permission.WAKE_LOCK: Permite que o aplicativo mantenha o dispositivo acordado.
  • android.permission.DISABLE_KEYGUARD: Permite que o aplicativo desabilite o bloqueio de tela.
  • android.permission.USE_FULL_SCREEN_INTENT: Necessária para exibir notificações heads-up.
  • android.permission.CALL_PHONE: Necessária para realizar chamadas telefônicas.

Você pode solicitar essas permissões em tempo de execução usando o ActivityCompat.requestPermissions. Certifique-se de verificar se o usuário já concedeu a permissão antes de solicitá-la novamente. Aqui está um exemplo de como você pode solicitar a permissão WAKE_LOCK:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WAKE_LOCK) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WAKE_LOCK}, WAKE_LOCK_PERMISSION_REQUEST_CODE);
}

Lembre-se de lidar com o resultado da solicitação de permissão no método onRequestPermissionsResult:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == WAKE_LOCK_PERMISSION_REQUEST_CODE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permissão concedida
        } else {
            // Permissão negada
        }
    }
}

É importante solicitar as permissões necessárias para garantir que seu aplicativo funcione corretamente e ofereça a melhor experiência de usuário.

Dicas Extras e Boas Práticas

  • Teste em diferentes dispositivos: O comportamento das notificações e da exibição de Activities pode variar entre diferentes dispositivos e versões do Android. É importante testar seu aplicativo em uma variedade de dispositivos para garantir que ele funcione corretamente.
  • Use um canal de notificação: Como mencionado anteriormente, é fundamental usar um canal de notificação para dispositivos com Android Oreo ou superior. Isso permite que o usuário controle as notificações do seu aplicativo e garante que as notificações de chamada sejam exibidas corretamente.
  • Considere o estado do aplicativo: Antes de exibir a Activity de chamada, verifique se o aplicativo está em primeiro plano ou em segundo plano. Se o aplicativo estiver em primeiro plano, você pode exibir a Activity diretamente. Se estiver em segundo plano, você pode exibir uma notificação heads-up.
  • Otimize a experiência do usuário: Certifique-se de que a Activity de chamada seja fácil de usar e intuitiva. O usuário deve ser capaz de atender ou rejeitar a chamada com facilidade.

Conclusão

E aí, pessoal! Chegamos ao fim do nosso guia sobre como mostrar uma Activity de chamada com a tela bloqueada no Android. Vimos como usar o Firebase Cloud Messaging (FCM) para enviar notificações de chamada, como criar um serviço para receber essas mensagens e como exibir a Activity de chamada mesmo quando o dispositivo está bloqueado. Também discutimos a importância de lidar com permissões e fornecemos algumas dicas extras para otimizar a experiência do usuário.

Espero que este guia tenha sido útil e que você consiga implementar essa funcionalidade no seu aplicativo de vídeo e voz. Se você tiver alguma dúvida ou precisar de ajuda, não hesite em perguntar! E lembre-se, o desenvolvimento Android pode ser desafiador, mas com as ferramentas e técnicas certas, você pode criar aplicativos incríveis.

Até a próxima e bons estudos! 😉