telefono salientes que para numeros numero llame llamadas entrantes desconocidos desbloquear contacto como celular bloquear bloqueadas android android-intent android-permissions incoming-call

salientes - ¿Cómo detectar llamadas entrantes en un dispositivo Android?



desbloquear llamadas entrantes (6)

Intento hacer una aplicación como, cuando llega una llamada al teléfono, quiero detectar el número. Debajo está lo que probé, pero no está detectando llamadas entrantes.

Quiero ejecutar mi MainActivity en segundo plano, ¿cómo puedo hacer eso?

Yo había dado el permiso en archivo manifest .

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

¿Hay algo más que debería proporcionar en el manifiesto?

public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_layout); } public class myPhoneStateChangeListener extends PhoneStateListener { @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); if (state == TelephonyManager.CALL_STATE_RINGING) { String phoneNumber = incomingNumber; } } } }


@Gabe Sechan, gracias por su código. Funciona bien excepto el onOutgoingCallEnded (). Nunca se ejecuta. Los teléfonos de prueba son Samsung S5 y Trendy. Hay 2 errores, creo.

Primero: falta un par de corchetes.

//.... case TelephonyManager.CALL_STATE_IDLE: //Went to idle- this is the end of a call. What type depends on previous state(s) if(lastState == TelephonyManager.CALL_STATE_RINGING){ //Ring but no pickup- a miss onMissedCall(context, savedNumber, callStartTime); } else{ // this one is missing if(isIncoming){ onIncomingCallEnded(context, savedNumber, callStartTime, new Date()); } else{ onOutgoingCallEnded(context, savedNumber, callStartTime, new Date()); } }// this one is missing break; //..

2nd: "lastState" no se actualiza por el "estado" si está al final de la función. Debe ser reemplazado a la primera línea de esta función por

public void onCallStateChanged(Context context, int state, String number) { int lastStateTemp = lastState; lastState = state; // todo replace all the "lastState" by lastStateTemp from here. if(lastStateTemp == state){ //No change, debounce extras return; } //....

Adicional He puesto "lastState" y "savedNumber" en preferencia compartida como sugirió.

Acabo de probarlo con los cambios anteriores. Error solucionado al menos en mis teléfonos.


ACTUALIZACIÓN: el share realmente increíble share ya no funciona a menos que solicite explícitamente al usuario que otorgue los permisos necesarios. Aquí hay un código que puede colocar en su actividad principal para solicitar estos permisos:

if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { // Permission has not been granted, therefore prompt the user to grant permission ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, MY_PERMISSIONS_REQUEST_READ_PHONE_STATE); } if (getApplicationContext().checkSelfPermission(Manifest.permission.PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED) { // Permission has not been granted, therefore prompt the user to grant permission ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS}, MY_PERMISSIONS_REQUEST_PROCESS_OUTGOING_CALLS); }

TAMBIÉN: Como alguien mencionó en un comentario debajo de la publicación de Gabe , tienes que agregar un pequeño fragmento de código, "android: enabled =" true ", al receptor para detectar llamadas entrantes cuando la aplicación no se está ejecutando actualmente en primer plano. :

<!--This part is inside the application--> <receiver android:name=".CallReceiver" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver>


Aquí hay un método simple que puede evitar el uso de PhonestateListener y otras complicaciones.
Así que aquí estamos recibiendo los 3 eventos de Android como RINGING, OFFHOOK e IDLE. Y para obtener todo el posible estado de llamada, necesitamos definir nuestros propios estados como RINGING, OFFHOOK, IDLE, FIRST_CALL_RINGING, SECOND_CALL_RINGING. Puede manejar todos los estados en una llamada telefónica.
Por favor, piense de una manera que estamos recibiendo eventos de Android y definiremos nuestros estados de llamada. Vea el código.

public class CallListening extends BroadcastReceiver { private static final String TAG ="broadcast_intent"; public static String incoming_number; private String current_state,previus_state,event; public static Boolean dialog= false; private Context context; private SharedPreferences sp,sp1; private SharedPreferences.Editor spEditor,spEditor1; public void onReceive(Context context, Intent intent) { //Log.d("intent_log", "Intent" + intent); dialog=true; this.context = context; event = intent.getStringExtra(TelephonyManager.EXTRA_STATE); incoming_number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER); Log.d(TAG, "The received event : "+event+", incoming_number : " + incoming_number); previus_state = getCallState(context); current_state = "IDLE"; if(incoming_number!=null){ updateIncomingNumber(incoming_number,context); }else { incoming_number=getIncomingNumber(context); } switch (event) { case "RINGING": Log.d(TAG, "State : Ringing, incoming_number : " + incoming_number); if((previus_state.equals("IDLE")) || (previus_state.equals("FIRST_CALL_RINGING"))){ current_state ="FIRST_CALL_RINGING"; } if((previus_state.equals("OFFHOOK"))||(previus_state.equals("SECOND_CALL_RINGING"))){ current_state = "SECOND_CALL_RINGING"; } break; case "OFFHOOK": Log.d(TAG, "State : offhook, incoming_number : " + incoming_number); if((previus_state.equals("IDLE")) ||(previus_state.equals("FIRST_CALL_RINGING")) || previus_state.equals("OFFHOOK")){ current_state = "OFFHOOK"; } if(previus_state.equals("SECOND_CALL_RINGING")){ current_state ="OFFHOOK"; startDialog(context); } break; case "IDLE": Log.d(TAG, "State : idle and incoming_number : " + incoming_number); if((previus_state.equals("OFFHOOK")) || (previus_state.equals("SECOND_CALL_RINGING")) || (previus_state.equals("IDLE"))){ current_state="IDLE"; } if(previus_state.equals("FIRST_CALL_RINGING")){ current_state = "IDLE"; startDialog(context); } updateIncomingNumber("no_number",context); Log.d(TAG,"stored incoming number flushed"); break; } if(!current_state.equals(previus_state)){ Log.d(TAG, "Updating state from "+previus_state +" to "+current_state); updateCallState(current_state,context); } } public void startDialog(Context context) { Log.d(TAG,"Starting Dialog box"); Intent intent1 = new Intent(context, NotifyHangup.class); intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent1); } public void updateCallState(String state,Context context){ sp = PreferenceManager.getDefaultSharedPreferences(context); spEditor = sp.edit(); spEditor.putString("call_state", state); spEditor.commit(); Log.d(TAG, "state updated"); } public void updateIncomingNumber(String inc_num,Context context){ sp = PreferenceManager.getDefaultSharedPreferences(context); spEditor = sp.edit(); spEditor.putString("inc_num", inc_num); spEditor.commit(); Log.d(TAG, "incoming number updated"); } public String getCallState(Context context){ sp1 = PreferenceManager.getDefaultSharedPreferences(context); String st =sp1.getString("call_state", "IDLE"); Log.d(TAG,"get previous state as :"+st); return st; } public String getIncomingNumber(Context context){ sp1 = PreferenceManager.getDefaultSharedPreferences(context); String st =sp1.getString("inc_num", "no_num"); Log.d(TAG,"get incoming number as :"+st); return st; } }


Esto es lo que uso para hacer esto:

Manifiesto:

<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> <!--This part is inside the application--> <receiver android:name=".CallReceiver" > <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver>

Mi detector de llamada reutilizable base

package com.gabesechan.android.reusable.receivers; import java.util.Date; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.telephony.TelephonyManager; public abstract class PhonecallReceiver extends BroadcastReceiver { //The receiver will be recreated whenever android feels like it. We need a static variable to remember data between instantiations private static int lastState = TelephonyManager.CALL_STATE_IDLE; private static Date callStartTime; private static boolean isIncoming; private static String savedNumber; //because the passed incoming is only valid in ringing @Override public void onReceive(Context context, Intent intent) { //We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number. if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) { savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER"); } else{ String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE); String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER); int state = 0; if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){ state = TelephonyManager.CALL_STATE_IDLE; } else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){ state = TelephonyManager.CALL_STATE_OFFHOOK; } else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){ state = TelephonyManager.CALL_STATE_RINGING; } onCallStateChanged(context, state, number); } } //Derived classes should override these to respond to specific events of interest protected abstract void onIncomingCallReceived(Context ctx, String number, Date start); protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start); protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end); protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start); protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end); protected abstract void onMissedCall(Context ctx, String number, Date start); //Deals with actual events //Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it''s answered, to IDLE when its hung up //Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up public void onCallStateChanged(Context context, int state, String number) { if(lastState == state){ //No change, debounce extras return; } switch (state) { case TelephonyManager.CALL_STATE_RINGING: isIncoming = true; callStartTime = new Date(); savedNumber = number; onIncomingCallReceived(context, number, callStartTime); break; case TelephonyManager.CALL_STATE_OFFHOOK: //Transition of ringing->offhook are pickups of incoming calls. Nothing done on them if(lastState != TelephonyManager.CALL_STATE_RINGING){ isIncoming = false; callStartTime = new Date(); onOutgoingCallStarted(context, savedNumber, callStartTime); } else { isIncoming = true; callStartTime = new Date(); onIncomingCallAnswered(context, savedNumber, callStartTime); } break; case TelephonyManager.CALL_STATE_IDLE: //Went to idle- this is the end of a call. What type depends on previous state(s) if(lastState == TelephonyManager.CALL_STATE_RINGING){ //Ring but no pickup- a miss onMissedCall(context, savedNumber, callStartTime); } else if(isIncoming){ onIncomingCallEnded(context, savedNumber, callStartTime, new Date()); } else{ onOutgoingCallEnded(context, savedNumber, callStartTime, new Date()); } break; } lastState = state; } }

Luego, para usarlo, simplemente obtenga una clase e implemente algunas funciones sencillas, cualquiera que sea el tipo de llamada que le interese:

public class CallReceiver extends PhonecallReceiver { @Override protected void onIncomingCallReceived(Context ctx, String number, Date start) { // } @Override protected void onIncomingCallAnswered(Context ctx, String number, Date start) { // } @Override protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) { // } @Override protected void onOutgoingCallStarted(Context ctx, String number, Date start) { // } @Override protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) { // } @Override protected void onMissedCall(Context ctx, String number, Date start) { // } }

Además, puede ver un escrito que hice sobre por qué el código es como está en mi blog . Enlace de Gist: https://gist.github.com/ftvs/e61ccb039f511eb288ee

EDITAR: actualizado a un código más simple, ya que he reelaborado la clase para mi propio uso


esto puede ayudarte y también agregar requerir permiso

public class PhoneListener extends PhoneStateListener { private Context context; public static String getincomno; public PhoneListener(Context c) { Log.i("CallRecorder", "PhoneListener constructor"); context = c; } public void onCallStateChanged (int state, String incomingNumber) { if(!TextUtils.isEmpty(incomingNumber)){ // here for Outgoing number make null to get incoming number CallBroadcastReceiver.numberToCall = null; getincomno = incomingNumber; } switch (state) { case TelephonyManager.CALL_STATE_IDLE: break; case TelephonyManager.CALL_STATE_RINGING: Log.d("CallRecorder", "CALL_STATE_RINGING"); break; case TelephonyManager.CALL_STATE_OFFHOOK: break; } } }


private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();

registrarse

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

y para anular el registro

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);