Como fazer uma ligação no Android e voltar à minha atividade quando a ligação é feita?

129

Estou iniciando uma atividade para fazer uma ligação, mas quando pressionei o botão 'encerrar ligação', ela não volta à minha atividade. Você pode me dizer como posso iniciar uma atividade de chamada que volta para mim quando o botão 'Terminar chamada' é pressionado? É assim que estou fazendo a ligação:

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

Respostas:

106

use um PhoneStateListener para ver quando a chamada termina. provavelmente será necessário acionar as ações do ouvinte para aguardar o início da chamada (aguarde até que seja alterado de PHONE_STATE_OFFHOOK para PHONE_STATE_IDLE novamente) e, em seguida, escreva um código para trazer seu aplicativo de volta ao estado IDLE.

pode ser necessário executar o ouvinte em um serviço para garantir que ele permaneça ativo e seu aplicativo seja reiniciado. algum código de exemplo:

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

Definição do ouvinte:

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");
        }
    }
}

No seu Manifest.xmlarquivo, adicione a seguinte permissão:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
moonlightcheese
fonte
10
Não esqueça a permissão. ;)
Gp2mv3
5
Como Gp2mv3 observou, não se esqueça de adicionar a permissão READ_PHONE_STATE ao AndroidManifest.xml.
Cooper
6
@moonlightcheese Você pode adicionar código para voltar ao nosso aplicativo a partir do aplicativo de chamada?
21713 Geek
isso é perigoso porque sempre vai abrir sua atividade da aplicação cada vez que você chamar
user924
49

Trata-se da pergunta feita pela Starter.

O problema com o seu código é que você não está passando o número corretamente.

O código deve 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);
    }
};

Não se esqueça de adicionar a permissão no arquivo de manifesto.

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

ou

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

para o número de emergência, caso DIALseja usado.

Pria
fonte
7
Eu estou tendo um momento difícil ver como seu código é diferente do código na pergunta original
Elias Saounkine
O código não é diferente. Você precisa adicionar a permissão no arquivo de manifesto.
Pria
4
android.permission.CALL_PRIVILEGED A permissão é concedida apenas a aplicativos do sistema não disponíveis no nível do aplicativo.
CoDe
e o que é isso? ele não vai voltar à sua atividade
user924
24

Tivemos o mesmo problema e conseguimos resolvê-lo usando a PhoneStateListenerpara identificar quando a chamada é encerrada, mas, além disso, precisávamos finish()da atividade original antes de iniciá-la novamente startActivity, caso contrário, o log de chamadas estaria à sua frente.

André Lima
fonte
4
você pode evitar isso usando um método diferente. se você criar um ContentObserver que observe o log de chamadas do Android, o aplicativo não será iniciado até que a alteração seja feita. Na verdade, tive que despejar o PhoneStateListener em favor desse modelo, pois meu aplicativo precisava de dados de log de chamadas e o ouvinte estava retornando antes que essas alterações fossem feitas. pastebin.com/bq2s9EVa
moonlightcheese
11
@ André: o seu link parece estar quebrado
aggregate1166877
Eu daria a você um milhão de reputação (se eu tivesse muito :)) Obrigado por fazer o meu dia!
keybee
1
O problema com os links que eu digo!
Dheeraj Bhaskar
Internet Archive para o resgate ... web.archive.org/web/20120123224619/http://umamao.com/questions/...
Básico
13

Eu achei o EndCallListener o exemplo mais funcional, para obter o comportamento descrito (finish (), chamar, reiniciar). Adicionei algumas SharedPreferences para que o Listener tivesse uma referência para gerenciar esse comportamento.

My OnClick, initialize e EndCallListener respondem apenas às chamadas do aplicativo. Outras chamadas 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);

        }

    }
}

adicione-os ao 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>

e algo assim em seu manifesto, se você precisar retornar à aparência antes da chamada

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

e coloque-os no seu '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 isso para iniciar o comportamento do seu onClick em myActivity, por exemplo, após 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();

}

Você deve descobrir que clicar em sua lista de números de telefone encerra sua atividade, faz a ligação para o número e retorna à sua atividade quando a ligação é encerrada.

Fazer uma chamada de fora do seu aplicativo enquanto ele ainda estiver por perto não reiniciará a sua atividade (a menos que seja o mesmo que o último número BParty chamado).

:)

TheSolarSheriff
fonte
5
Desculpe, mas este código parece um pouco feio. Obrigado pela resposta embora
Pierre
7

você pode usar startActivityForResult ()

yakr
fonte
1
Usando o Android 5.0, o método onActivityResult é chamado imediatamente, a chamada é iniciada !!
Panciz
6

Esta é a solução do meu ponto 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);

    }

Obviamente, na definição de atividade (classe), você precisa implementar o View.OnClickListener.

cikabole
fonte
6

Aqui está o meu exemplo: primeiro, o usuário pode escrever o número que deseja discar, pressionar um botão de chamada e ser direcionado para o telefone. Após o cancelamento da chamada, o usuário é enviado de volta ao aplicativo. Para isso, o botão precisa ter um método onClick ('makePhoneCall' neste exemplo) no xml. Você também precisa registrar a permissão no manifesto.

Manifesto

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

Atividade

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
fonte
você nem sabe do que está falando. READ_PHONE_STATE - você não o usa no seu código de exemplo, por que o adicionou? é claro que ele irá retornar de volta para sua atividade da aplicação, se você pressionar o botão de cancelamento, mas o autor da pergunta sobre como voltar à atividade após chamada foi aceito
user924
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
fonte
5

Se você for usar um ouvinte, precisará adicionar essa permissão também ao manifesto.

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

Dentro do PhoneStateListener depois de ver a chamada terminar, use melhor:

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

Onde CallDispatcherActivity é a atividade em que o usuário iniciou uma chamada (para um despachante de serviço de táxi, no meu caso). Isso apenas remove o aplicativo de telefonia Android da parte superior, o usuário retorna em vez do código feio que eu vi aqui.

Dmitri Novikov
fonte
1
E não se esqueça de remover o ouvinte após a ligação, assim:((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov
Tentei usar sua abordagem, mas a atividade (chamada ControlPanel) não está sendo reativada. O visor continua mostrando a interface do discador do telefone e os registradores nos pontos de entrada onResume e onNewIntent no ControlPanel ficam completamente silenciosos. Aqui é a intenção: Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);. Devo salientar que o PhoneStateListener também está no ControlPanel. Ou seja, meu objetivo é restaurar a interface do usuário para o estado em que estava antes de iniciar a ligação. Alguma sugestão?
PeteH #
Tente fazer logon na sua implementação PhoneStateListener.
Dmitri Novikov
3

Para retornar ao seu Activity, você precisará ouvir TelephonyStates. Nesse caso, listenervocê pode enviar um Intentpara reabrir o seu Activityquando o telefone estiver ocioso.

Pelo menos é assim que eu vou fazer.

Aimeric
fonte
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
fonte
2

Tente usar:

finish();

no final da atividade. Ele o redirecionará para sua atividade anterior.

Ankit Kedia
fonte
2

Quando PhoneStateListeneré usado, é necessário garantir que a PHONE_STATE_IDLEseguinte PHONE_STATE_OFFHOOKseja usada para acionar a ação a ser executada após a chamada. Se o gatilho acontecer ao ver PHONE_STATE_IDLE, você o fará antes da chamada. Porque você verá o estado mudarPHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.

PonMaran
fonte
não é possível que o aplicativo pare quando a tela de chamada em andamento for aberta?
lisovaccaro 21/01
Objeto ouvinte uma vez set para ouvir o TelephonyManager com ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE)vai continuar a ouvir o estado do telefone e ser ativo até ser explicitamente interrompido com((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran
2

// no setonclicklistener coloque 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);

// dê permissão para chamada no manifesto:

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

@Dmitri Novikov, FLAG_ACTIVITY_CLEAR_TOPlimpa qualquer instância ativa em cima da nova. Portanto, ele pode encerrar a instância antiga antes de concluir o processo.

PonMaran
fonte
1

Adicione este é o seu xml: android:autoLink="phone"

Roman Marius
fonte
2
Por favor elabore. "Qual xml"?
Anas Azeem 19/10/2013
1

Passos:

1) Adicione as permissões necessárias no Manifest.xmlarquivo.

<!--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) Crie um ouvinte para as alterações de estado do telefone.

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) Inicialize o ouvinte no seu OnCreate

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

mas se você deseja retomar o último estado do aplicativo ou trazê-lo de volta da pilha traseira , substitua FLAG_ACTIVITY_CLEAR_TOPporFLAG_ACTIVITY_SINGLE_TOP

Referenciar esta resposta

Sami El-Tamawy
fonte
0

Ao iniciar sua chamada, ela fica bem.

No entanto, há uma diferença entre o Android 11+ e a versão mais recente, trazendo seu aplicativo para a frente.

Android 10 ou menos, você precisa iniciar uma nova intenção, Android 11+, basta usar BringTaskToFront

No estado de chamada 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);
}

Eu defino o MyActivity.MyActivityTaskIdquando faço a chamada da minha atividade dessa forma, isso não funciona, defina essa variável na página de atividades pai da página na qual você deseja voltar.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId é uma variável estática na minha classe de atividade

public static int MyActivityTaskId = 0;

Espero que isso funcione para você. Eu uso o código acima de maneira um pouco diferente, abro meu aplicativo assim que a chamada é atendida para que o usuário possa ver os detalhes do chamador.

Eu configurei algumas coisas no AndroidManifest.xmltambém:

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

e permissões:

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

Faça perguntas se ou quando você ficar preso.

Pierre
fonte