¿Cómo hacer una llamada telefónica en Android y volver a mi actividad cuando termine la llamada?

129

Estoy iniciando una actividad para hacer una llamada telefónica, pero cuando presioné el botón 'finalizar llamada', no vuelve a mi actividad. ¿Puede decirme cómo puedo iniciar una actividad de llamada que vuelve a mí cuando se presiona el botón 'Finalizar llamada'? Así es como estoy haciendo la llamada telefónica:

    String url = "tel:3334444";
    Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(url));
hap497
fuente

Respuestas:

106

use PhoneStateListener para ver cuándo finaliza la llamada. lo más probable es que necesite activar las acciones de escucha para esperar a que comience la llamada (espere hasta que cambie de PHONE_STATE_OFFHOOK a PHONE_STATE_IDLE nuevamente) y luego escriba algún código para que su aplicación vuelva a funcionar en el estado IDLE.

es posible que deba ejecutar el escucha en un servicio para asegurarse de que se mantenga activo y que se reinicie su aplicación. algún código de ejemplo:

EndCallListener callListener = new EndCallListener();
TelephonyManager mTM = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);

Definición de oyente:

private class EndCallListener extends PhoneStateListener {
    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        if(TelephonyManager.CALL_STATE_RINGING == state) {
            Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
        }
        if(TelephonyManager.CALL_STATE_OFFHOOK == state) {
            //wait for phone to go offhook (probably set a boolean flag) so you know your app initiated the call.
            Log.i(LOG_TAG, "OFFHOOK");
        }
        if(TelephonyManager.CALL_STATE_IDLE == state) {
            //when this state occurs, and your flag is set, restart your app
            Log.i(LOG_TAG, "IDLE");
        }
    }
}

En su Manifest.xmlarchivo agregue el siguiente permiso:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
moonlightcheese
fuente
10
No olvides el permiso. ;)
Gp2mv3
55
Como ha señalado Gp2mv3, no olvide agregar el permiso READ_PHONE_STATE al AndroidManifest.xml.
Cooper
66
@moonlightcheese ¿Puede agregar código para volver a nuestra aplicación desde la aplicación de llamada?
Geek
esto es peligroso porque siempre abrirá la actividad de su aplicación cada vez que llame
usuario924
49

Esto se refiere a la pregunta formulada por Starter.

El problema con su código es que no está pasando el número correctamente.

El código debe ser:

private OnClickListener next = new OnClickListener() {

     public void onClick(View v) {
        EditText num=(EditText)findViewById(R.id.EditText01); 
        String number = "tel:" + num.getText().toString().trim();
        Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(number)); 
        startActivity(callIntent);
    }
};

No olvide agregar el permiso en el archivo de manifiesto.

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

o

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

para número de emergencia en caso de que DIALse utilice

Pria
fuente
77
Me está costando ver cómo su código es diferente del código de la pregunta original
Elijah Saounkine,
El código no es diferente. Debe agregar el permiso en el archivo de manifiesto.
Pria
44
android.permission.CALL_PRIVILEGED El permiso solo se otorga a las aplicaciones del sistema que no están disponibles a nivel de aplicación.
Código
¿y qué es eso? no volverá a su actividad
usuario924
24

Tuvimos el mismo problema y logramos resolverlo utilizando a PhoneStateListenerpara identificar cuándo finaliza la llamada, pero adicionalmente tuvimos que realizar finish()la actividad original antes de comenzar de nuevo startActivity, de lo contrario el registro de llamadas estaría frente a él.

André Lima
fuente
44
puedes evitar esto usando un método diferente. si crea un ContentObserver que observe el registro de llamadas de Android, la aplicación no se iniciará hasta que se realice el cambio en el registro de llamadas. De hecho, tuve que volcar PhoneStateListener a favor de este modelo, ya que mi aplicación necesitaba datos de registro de llamadas, y el oyente regresaba antes de que se realizaran esos cambios. pastebin.com/bq2s9EVa
moonlightcheese
11
@ André: su enlace parece estar roto
agregado1166877
Te daría un millón de reputación (si tuviera mucho :)) ¡Gracias por alegrarme el día!
keybee
1
El problema con los enlaces que digo!
Dheeraj Bhaskar
Archivo de Internet al rescate ... web.archive.org/web/20120123224619/http://umamao.com/questions/…
Básico
13

Encontré que EndCallListener es el ejemplo más funcional, para obtener el comportamiento descrito (terminar (), llamar, reiniciar) agregué algunas SharedPreferences para que el oyente tuviera una referencia para administrar este comportamiento.

My OnClick, initialise y EndCallListener solo responden las llamadas desde la aplicación. Otras llamadas ignoradas.

import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;

public class EndCallListener extends PhoneStateListener {

private String TAG ="EndCallListener";
private int     LAUNCHED = -1;

SharedPreferences prefs = PreferenceManager
                            .getDefaultSharedPreferences(
                                myActivity.mApp.getBaseContext());

SharedPreferences.Editor _ed = prefs.edit();

@Override
    public void onCallStateChanged(int state, String incomingNumber) {
    String _prefKey = myActivity.mApp                          
                      .getResources().getString(R.string.last_phone_call_state_key),
    _bPartyNumber = myActivity.mApp                           
                      .getResources().getString(R.string.last_phone_call_bparty_key);

    int mLastCallState = prefs.getInt(_prefKey, LAUNCHED);

    //Save current call sate for next call
    _ed.putInt(_prefKey,state);
    _ed.commit();

        if(TelephonyManager.CALL_STATE_RINGING == state) {
            Log.i(TAG, " >> RINGING, number: " + incomingNumber);
        }
        if(TelephonyManager.CALL_STATE_IDLE == state && mLastCallState != LAUNCHED ) {
            //when this state occurs, and your flag is set, restart your app

            if (incomingNumber.equals(_bPartyNumber) == true) {
                //Call relates to last app initiated call
            Intent  _startMyActivity =  
               myActivity.mApp                               
               .getPackageManager()                                  
               .getLaunchIntentForPackage(
                 myActivity.mApp.getResources()
                 .getString(R.string.figjam_package_path));

_startMyActivity.setAction(                                     
        myActivity.mApp.getResources()
        .getString(R.string.main_show_phone_call_list));

                myActivity.mApp
                        .startActivity(_startMyActivity);
                Log.i(TAG, "IDLE >> Starting MyActivity with intent");
            }
            else
                Log.i(TAG, "IDLE after calling "+incomingNumber);

        }

    }
}

agréguelos a strings.xml

<string name="main_show_phone_call_list">android.intent.action.SHOW_PHONE_CALL_LIST</string>
<string name="last_phone_call_state_key">activityLpcsKey</string>
<string name="last_phone_call_bparty_key">activityLpbpKey</string>

y algo así en su Manifiesto si necesita volver a la apariencia antes de la llamada

  <activity android:label="@string/app_name" android:name="com.myPackage.myActivity" 
      android:windowSoftInputMode="stateHidden"
        android:configChanges="keyboardHidden" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <action android:name="android.intent.action.SHOW_PHONE_CALL_LIST" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
  </activity>

y ponerlos en tu 'myActivity'

public static Activity mApp=null; //Before onCreate()
  ...
onCreate( ... ) {
  ...
if (mApp == null) mApp = this; //Links your resources to other classes
  ...
    //Test if we've been called to show phone call list
    Intent _outcome = getIntent();
    String _phoneCallAction = mApp.getResources().getString(R.string.main_show_phone_call_list);
    String _reqAction = _outcome.getAction();//Can be null when no intent involved

         //Decide if we return to the Phone Call List view
         if (_reqAction != null &&_reqAction.equals(_phoneCallAction) == true) {
                         //DO something to return to look and feel
         }

  ...
        myListView.setOnItemClickListener(new OnItemClickListener() { //Act on item when selected
             @Override
             public void onItemClick(AdapterView<?> a, View v, int position, long id) {

                 myListView.moveToPosition(position);
                 String _bPartyNumber = "tel:"+myListView.getString(myListView.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); 

                 //Provide an initial state for the listener to access.
                 initialiseCallStatePreferences(_bPartyNumber);

                 //Setup the listener so we can restart myActivity
                    EndCallListener _callListener = new EndCallListener();
                    TelephonyManager _TM = (TelephonyManager)mApp.getSystemService(Context.TELEPHONY_SERVICE);

                    _TM.listen(_callListener, PhoneStateListener.LISTEN_CALL_STATE);

                         Intent _makeCall = new Intent(Intent.ACTION_CALL, Uri.parse(_bPartyNumber));

                 _makeCall.setComponent(new ComponentName("com.android.phone","com.android.phone.OutgoingCallBroadcaster"));
                    startActivity(_makeCall);                           
                finish();
              //Wait for call to enter the IDLE state and then we will be recalled by _callListener
              }
        });


}//end of onCreate()

use esto para iniciar el comportamiento de su onClick en myActivity, por ejemplo, después de onCreate ()

private void initialiseCallStatePreferences(String _BParty) {
    final int LAUNCHED = -1;
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
                                mApp.getBaseContext());
    SharedPreferences.Editor _ed = prefs.edit();

    String _prefKey = mApp.getString(R.string.last_phone_call_state_key),
           _bPartyKey = mApp.getString(R.string.last_phone_call_bparty_key);

    //Save default call state before next call
        _ed.putInt(_prefKey,LAUNCHED);
        _ed.putString(_bPartyKey,_BParty);
        _ed.commit();

}

Debería descubrir que al hacer clic en su lista de números de teléfono finaliza su actividad, realiza la llamada al número y vuelve a su actividad cuando finaliza la llamada.

Hacer una llamada desde fuera de su aplicación mientras está activa no reiniciará su actividad (a menos que sea el mismo que el último número de BParty llamado).

:)

TheSolarSheriff
fuente
55
Lo siento, pero este código se ve algo feo. Sin embargo
Pierre
7

puedes usar startActivityForResult ()

yakr
fuente
1
Usando Android 5.0, el método onActivityResult es llamar inmediatamente, ¡comienza la llamada!
Panciz
6

Esta es la solución desde mi punto de vista:

ok.setOnClickListener(this);
@Override
public void onClick(View view) {
    if(view == ok){
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:" + num));
        activity.startActivity(intent);

    }

Por supuesto, en la definición de Actividad (clase) debe implementar View.OnClickListener.

cikabole
fuente
6

Aquí está mi ejemplo, primero el usuario puede escribir el número que desea marcar y luego presiona un botón de llamada y se lo dirige al teléfono. Después de la cancelación de la llamada, el usuario vuelve a la aplicación. Para esto, el botón debe tener un método onClick ('makePhoneCall' en este ejemplo) en el xml. También debe registrar el permiso en el manifiesto.

Manifiesto

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

Actividad

import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

public class PhoneCall extends Activity {

    EditText phoneTo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_phone_call);

        phoneTo = (EditText) findViewById(R.id.phoneNumber);

    }
    public void makePhoneCall(View view) {




        try {
            String number = phoneTo.getText().toString();
            Intent phoneIntent = new Intent(Intent.ACTION_CALL);
            phoneIntent.setData(Uri.parse("tel:"+ number));
            startActivity(phoneIntent);


        } catch (android.content.ActivityNotFoundException ex) {
            Toast.makeText(PhoneCall.this,
                    "Call failed, please try again later!", Toast.LENGTH_SHORT).show();
        }
    }

}

XML

 <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:ems="10"
        android:id="@+id/phoneNumber"
        android:layout_marginTop="67dp"
        android:layout_below="@+id/textView"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Call"
        android:id="@+id/makePhoneCall"
        android:onClick="makePhoneCall"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" />
Oyee
fuente
Ni siquiera de lo que estás hablando. READ_PHONE_STATE: no lo usa en su código de ejemplo, ¿por qué lo agregó? por supuesto, lo devolverá a la actividad de su aplicación si presiona el botón de cancelación, pero el autor de la pregunta preguntó cómo volver a la actividad después de que se aceptara la llamada
usuario924
6
@Override
public void onClick(View view) {
    Intent phoneIntent = new Intent(Intent.ACTION_CALL);
    phoneIntent.setData(Uri.parse("tel:91-000-000-0000"));
    if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    startActivity(phoneIntent);
}
Laxman Bhattarai
fuente
5

Si va a utilizar un oyente, también deberá agregar este permiso al manifiesto.

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

Dentro de PhoneStateListener después de ver que la llamada ha terminado, mejor uso:

Intent intent = new Intent(CallDispatcherActivity.this, CallDispatcherActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

Donde CallDispatcherActivity es la actividad en la que el usuario ha lanzado una llamada (a un despachador de servicios de taxi, en mi caso). Esto simplemente elimina la aplicación de telefonía Android de la parte superior, el usuario regresa en lugar del código feo que vi aquí.

Dmitri Novikov
fuente
1
Y no se olvide de eliminar al oyente después de finalizar la llamada telefónica, de esta manera:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov
Intenté usar su enfoque pero la actividad (llamada ControlPanel) no se está reactivando. La pantalla continúa mostrando la interfaz del marcador telefónico y los registradores en los puntos de entrada onResume y onNewIntent dentro de ControlPanel son completamente silenciosos. Esta es la intención: Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Debo señalar que PhoneStateListener también está dentro de ControlPanel. Es decir, mi objetivo es restaurar la IU al estado en que estaba antes de iniciar la llamada telefónica. ¿Alguna sugerencia?
PeteH
Intente iniciar sesión dentro de su implementación PhoneStateListener.
Dmitri Novikov
3

Para volver a su Activity, tendrá que escuchar TelephonyStates. En eso listener, puede enviar un mensaje Intentpara volver a abrir una Activityvez que el teléfono esté inactivo.

Al menos así es como lo haré.

Aimeric
fuente
3
  Intent callIntent = new Intent(Intent.ACTION_CALL);  
  callIntent.setData(Uri.parse("tel:"+number));  
   startActivity(callIntent);   

 **Add permission :**

 <uses-permission android:name="android.permission.CALL_PHONE" />          
ritesh4326
fuente
2

Intenta usar:

finish();

Al final de la actividad. Te redirigirá a tu actividad anterior.

Ankit Kedia
fuente
2

Cuando PhoneStateListenerse usa, es necesario asegurarse de que se PHONE_STATE_IDLEsiga a PHONE_STATE_OFFHOOKpara activar la acción que se realizará después de la llamada. Si el disparador ocurre al ver PHONE_STATE_IDLE, terminará haciéndolo antes de la llamada. Porque verás el cambio de estadoPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.

PonMaran
fuente
¿No es posible que la aplicación se detenga cuando se abra la pantalla de llamadas en curso?
lisovaccaro
El objeto de escucha una vez configurado para escuchar el TelephonyManager ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE)continuará escuchando el estado del teléfono y estará activo hasta que se detenga explícitamente con((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran
2

// en setonclicklistener pon este código:

EditText et_number=(EditText)findViewById(R.id.id_of_edittext); 
String my_number = et_number.getText().toString().trim();
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(my_number)); 
startActivity(callIntent);

// dar permiso para la llamada en manifiesto:

<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>
Hiren Patel
fuente
1

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPborra cualquier instancia activa además de la nueva. Por lo tanto, puede finalizar la instancia anterior antes de que complete el proceso.

PonMaran
fuente
1

Agregue este es su xml: android:autoLink="phone"

Marius romano
fuente
2
Por favor elabora. "¿Qué xml"?
Anas Azeem
1

Pasos:

1) Agregue los permisos requeridos en el Manifest.xmlarchivo.

<!--For using the phone calls -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!--For reading phone call state-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

2) Crear un oyente para los cambios de estado del teléfono.

public class EndCallListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
    if(TelephonyManager.CALL_STATE_RINGING == state) {
    }
    if(TelephonyManager.CALL_STATE_OFFHOOK == state) {
        //wait for phone to go offhook (probably set a boolean flag) so you know your app initiated the call.
    }
    if(TelephonyManager.CALL_STATE_IDLE == state) {
        //when this state occurs, and your flag is set, restart your app
    Intent i = context.getPackageManager().getLaunchIntentForPackage(
                            context.getPackageName());
    //For resuming the application from the previous state
    i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

    //Uncomment the following if you want to restart the application instead of bring to front.
    //i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    context.startActivity(i);
    }
}
}

3) Inicialice al oyente en su OnCreate

EndCallListener callListener = new EndCallListener();
TelephonyManager mTM = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
mTM.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);

pero si desea reanudar el último estado de su aplicación o recuperarla de la pila posterior , reemplácela FLAG_ACTIVITY_CLEAR_TOPconFLAG_ACTIVITY_SINGLE_TOP

Referencia esta respuesta

Sami El-Tamawy
fuente
0

Al comenzar su llamada, se ve bien.

Sin embargo, hay una diferencia entre Android 11+ y versiones anteriores para llevar su aplicación al frente.

Android 10 o menos necesita comenzar una nueva intención, Android 11+ simplemente usa BringTaskToFront

En el estado de llamada IDLE:

if (Build.VERSION.SDK_INT >= 11) {
    ActivityManager am = (ActivityManager) activity.getSystemService(Activity.ACTIVITY_SERVICE);
    am.moveTaskToFront(MyActivity.MyActivityTaskId, ActivityManager.MOVE_TASK_WITH_HOME);
} else {
    Intent intent = new Intent(activity, MyActivity.class);
    activity.startActivity(intent);
}

Establecí el MyActivity.MyActivityTaskIdcuando hago la llamada en mi actividad de esta manera, si esto no funciona, establezca esta variable en la página de actividad principal de la página a la que desea volver.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId es una variable estática en mi clase de actividad

public static int MyActivityTaskId = 0;

Espero que esto funcione para tí. Utilizo el código anterior un poco diferente, abro mi aplicación tan pronto como se responde la llamada para que el usuario pueda ver los detalles de la persona que llama.

También he puesto algunas cosas en el AndroidManifest.xml:

/*Dont really know if this makes a difference*/
<activity android:name="MyActivity" android:taskAffinity="" android:launchMode="singleTask" />

y permisos:

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

Por favor haga preguntas si o cuando se atasca.

Pierre
fuente