A facilidade da plataforma Android me encanta muito, nunca programei com nada tão bacana. Por isso, vou falar um pouquinho sobre como capturar eventos do sistema utilizando BroadcastReceivers. A classe android.content.BroadcastReceiver é utilizada para receber eventos de sistema (ou nossos próprios) e tratá-los em background. Ela não possui interface gráfica associada e possui um tempo de vida muito curto (cerca de 10 segundo), então se quisermos mostrar algum feedback pro usuário devemos delegar isso pra uma Activity.
Para implementarmos um BroadcastReceiver basta criar uma classe que a estenda, implementar o método onReceive(Context, Intent) e registrá-la com a tag <receiver> AndroidManifest.xml ou no código através do método context.registerReceiver(receiver, filtro). Para desativar podemos utilizar uma chamada para context.unregisterReceiver(receiver). Se quisermos enviar nossa própria mensagem de broadcast, podemos chamar o método sendBroadcast(Intent).
No nosso exemplo, capturaremos as mudanças de estado do telefone. Ou seja, quando for feita, recebida ou terminada uma ligação, nosso BroadcastReceiver entrará em ação.
Primeiro, crie a classe conforme abaixo:
public class InterceptCall extends BroadcastReceiver { public void onReceive(Context ctx, Intent it) { String estado = it.getStringExtra("state"); String num = it.getStringExtra("incoming_number"); String msg = null; if (estado.equals("RINGING")){ msg = "O número "+ num +" está chamando."; } else if (estado.equals("OFFHOOK")){ msg = "Em ligação."; } else if (estado.equals("IDLE")){ if (num != null){ msg = "Chamada não atendida de "+ num; } else { msg = "Chamada atendida, foi terminada."; } } Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show(); } }Com esse receiver, capturamos a mudança de estado do telefone em ligações. A Intent que o dispara tem dois extras: state e incoming_number. O primeiro indica o estado do telefone e o segundo o número do telefone de quem está ligando. O telefone vai para o estado RINGING (tocando) quando o telefone está recebendo a ligação. Ao atender ou fazer uma chamada o telefone vai para o estado OFFHOOK (fora do gancho). E por último, ao terminar uma ligação o telefone volta para o seu estado padrão, IDLE (parado).
Notem que nem OFFHOOK e nem IDLE quando não se atende a ligação, contam com o número do telefone que o chamou.
Para finalizar, basta registrarmos o nosso BroadcastReceiver no AndroidManifest.xml, dentro da tag <application>, conforme abaixo:
<receiver android:name="InterceptCall"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </receiver>Também adicione a permissão para ler o estado da ligação no AndroidManifest.xml FORA DA TAG
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>Pronto! Agora é só brincar com os demais eventos do sistema.
4br4ç05,
nglauber
17 comentários:
E como eu faço para testar o que foi feito? poderia explicar ?
Para testar, se você estiver usando o emulador, basta ir na perspectiva DDMS do Eclipse, selecionar a guia "Emulator Control". Na seção "Telephony Actions" você digita um número qualquer (será o número do telefone que estará chamando o emulador) e seleciona o radio button "Voice", depois é só clicar no botão "Call". Isso simulará uma chamada telefônica ao emulador.
Se for no telefone, é só discar pra o telefone que tem a aplicação :)
Mais a seção "Telephony Actions" não esta habilitada para eu selecionar
Olá Anônimo Anônimo,
No Eclipse, vá até o menu Window > Show view > Other.
Quando abrir a janela "Show View", na pasta Android, selecione "Emulator Control".
4br4ç05,
nglauber
Obrigado Nelson,
Achei o que estava procurando. Devagar vou aprendendo.
Grato.
boas,
se tiver um boadcast com varios receivers a tratar de eventos diferentes e um deles finalizar esse broadcast. o que acontece?
obrigado
Fernando
Olá anônimo,
Quando um evento do sistema acontece, o broadcast que está ouvindo aquele evento é instânciado. O método onReceive é chamado, e ao completar sua execução, aquela instância do broadcast receiver é desalocada da memória.
Então não existe (que eu saiba) "finalizar esse broadcast" ele será finalizado automaticamente quando o método onReceive terminar.
4br4ç05,
nglauber
Nelson, PARABÉNS!!!!!!
Com as orientações,consegui pela primeira vez ver o estado do telefone.
Se for possível gostaria de sua ajuda??
Preciso retornar ao aplicativo que originou o receiver sempre que o estado = IDLE.
Desde já agradeço.
Luiz Carlos
Oi Luiz,
Tenta dar um startActivity para a Activity que você quer....
4br4ç05,
Glauber
Nelson, boa tarde.
Obrigado pela resposta tão rápida.
Desculpe a "IGNORÂNCIA DO MACACO" mas onde coloco a
no receiver:
@Override
public void onReceive(Context ctx, Intent intent) {
String estado = intent.getStringExtra("state");
String num = intent.getStringExtra("incoming_number");
String msg = null;
if (estado.equals("RINGING")){
msg = "O número "+ num +" está chamando.";
} else if (estado.equals("OFFHOOK")){
msg = "Em ligação.";
} else if (estado.equals("IDLE")){
if (num != null){
msg = "Chamada não atendida de "+ num;
} else {
msg = "Chamada atendida, foi terminada.";
}
}
Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show();
}
Grato, Luiz Carlos
Nelson, boa tarde.
Resolvi a ultimo problema assim:
Intent iAlarm = new Intent( ctx, MainActivity.class ); iAlarm.addFlags(Intent.FLAG_FROM_BACKGROUND); iAlarm.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); iAlarm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ctx.startActivity(iAlarm);
Fui tentando tentando até dar certo.
Caso queira corrigir ou simplificar esteja a vontade afinal o código é seu.
Muito obrigado, se precisar te em comodo novamente.
Muito, Muito OBRIGADO.
Luiz Carlos
Boa noite,
Mais uma matéria muito bem explicada.
Parabéns
Quando começei a estudar Android e mais concretamente o BroadcastReceiver não percebia quem difenia o evento. Só depois me apercebi que quem fazia isso era o Android Manifest hehehhe
No inicio eu pensava que era dentro da classe do BroadcastReceiver. hehehe
Cumprimentos
Malainho
Não existe nenhuma maneira de "pegar" o número ao efetuar chamadas, ou seja no estado OFFHOOK? Parabéns pelo post, muito bom.
Oi Anônimo,
Quando você está recebendo uma ligação, você pode pegar o número no estado de RINGING.
Para pegar ao efetuar chamadas você deve capturar a ação NEW_OUTGOING_CALL (http://developer.android.com/reference/android/content/Intent.html#ACTION_NEW_OUTGOING_CALL) ao invés do PHONE_STATE. E no receiver obter o número pelo EXTRA_PHONE_NUMBER.
4br4ç05,
nglauber
Muito obrigado mesmo! Deu certinho
É possível impedir o recebimento de uma chamada ou pelo menos cancelar? Tentei usar o abortBroadcast(), setResultData(null), aumentar a prioridade, mas não funcionou.
Oi Anônimo,
Pela minha demora acho que você já resolveu, mas para futuras consultas, já tentou isso aqui?
http://stackoverflow.com/questions/20965702/end-incoming-call-programmatically
4br4ç05,
nglauber
Postar um comentário