안드로이드에서 전화를 걸고 통화가 끝나면 내 활동으로 돌아 오는 방법은 무엇입니까?


129

전화를 걸기위한 활동을 시작하고 있지만 '통화 종료'버튼을 눌렀을 때 내 활동으로 돌아 가지 않습니다. '통화 종료'버튼을 눌렀을 때 되돌아 오는 통화 활동을 시작하려면 어떻게해야합니까? 이것이 내가 전화하는 방법입니다.

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

답변:


106

PhoneStateListener를 사용하여 호출이 종료 된시기를 확인하십시오. 호출이 시작될 때까지 (PHONE_STATE_OFFHOOK에서 PHONE_STATE_IDLE로 다시 변경 될 때까지 기다린 후) 리스너 작업을 트리거 한 다음 일부 코드를 작성하여 앱을 IDLE 상태로 다시 가져와야합니다.

서비스에서 리스너를 실행하여 작동 상태를 유지하고 앱을 다시 시작해야 할 수 있습니다. 예제 코드 :

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

리스너 정의 :

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

당신의에서 Manifest.xml파일을 다음과 같은 권한을 추가 :

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

10
허가를 잊지 마십시오. ;)
Gp2mv3 2016 년

5
Gp2mv3이 언급했듯이 AndroidManifest.xml에 READ_PHONE_STATE 권한을 추가하는 것을 잊지 마십시오.
Cooper

6
@moonlightcheese 통화 앱에서 앱으로 돌아 오는 코드를 추가 할 수 있습니까?
Geek

전화 할 때마다 항상 앱 활동이 열리기 때문에 위험합니다
user924

49

이것은 스타터가 묻는 질문에 관한 것입니다.

코드의 문제는 숫자를 제대로 전달하지 못한다는 것입니다.

코드는 다음과 같아야합니다.

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

매니페스트 파일에 권한을 추가하는 것을 잊지 마십시오.

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

또는

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

경우에 긴급 전화 번호 DIAL가 사용됩니다.


7
코드가 원래 질문의 코드와 어떻게
다른지보기가 힘듭니다.

코드는 다르지 않습니다. 매니페스트 파일에 권한을 추가해야합니다.
Pria

4
android.permission.CALL_PRIVILEGED 권한은 앱 수준에서 사용할 수없는 시스템 앱에만 부여됩니다.
CoDe

그게 뭐야? 그것은 당신의 활동으로 다시 돌아 가지 않을 것입니다
user924

24

우리는 같은 문제가 있었고 PhoneStateListener호출이 끝나는 시간을 식별하기 위해 a 를 사용하여 문제를 해결할 수 있었지만 finish()다시 시작하기 전에 원래 활동을 수행해야했습니다 startActivity. 그렇지 않으면 호출 로그가 앞에 있습니다.


4
다른 방법을 사용하면이를 피할 수 있습니다. Android 통화 로그를 관찰하는 ContentObserver를 빌드하면 통화 로그가 변경 될 때까지 앱이 시작되지 않습니다. 내 응용 프로그램에 통화 로그 데이터가 필요했기 때문에 실제로이 모델을 위해 PhoneStateListener를 덤프해야했으며 변경 사항이 적용되기 전에 리스너가 반환되었습니다. pastebin.com/bq2s9EVa
moonlightcheese

11
앙드레 @ : 귀하의 링크가 깨져서 표시
aggregate1166877

나는 당신에게 백만의 명성을 줄 것입니다 (많은 경우 :)) 내 하루를 주셔서 감사합니다!
keybee

1
내가 말하는 링크의 문제!
Dheeraj Bhaskar


13

EndCallListener가 가장 기능적인 예라는 것을 발견했습니다. (finish (), call, restart) 설명 된 동작을 얻기 위해 몇 가지 SharedPreferences를 추가하여 리스너가이 동작을 관리하기위한 참조를 갖도록했습니다.

내 OnClick, 초기화 및 EndCallListener는 앱의 호출에만 응답합니다. 다른 통화는 무시되었습니다.

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

        }

    }
}

이것을 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>

통화 전에 모양과 느낌으로 돌아 가야 할 경우 매니페스트에서 이와 같은

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

이것을 당신의 '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()

이것을 사용하여 myActivity에서 onClick의 동작을 초기화하십시오 (예 : 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();

}

전화 번호 목록을 클릭하면 활동이 완료되고 해당 번호로 전화를 걸고 통화가 종료되면 활동으로 돌아갑니다.

주변에있는 동안 앱 외부에서 전화를 걸더라도 활동이 다시 시작되지 않습니다 (마지막 BParty 번호와 동일하지 않은 경우).

:)


5
죄송하지만이 코드는 다소보기 흉하게 보입니다. 그래도 답변 주셔서 감사합니다
Pierre

7

startActivityForResult ()를 사용할 수 있습니다


1
안드로이드 5.0을 사용하면 onActivityResult 메소드가 즉시 호출이 시작됩니다!
Panciz

6

이것은 내 관점에서 해결책입니다.

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

    }

물론 활동 (클래스) 정의에서는 View.OnClickListener 구현해야합니다.


6

예를 들어, 먼저 사용자가 전화를 걸려는 번호를 쓴 다음 통화 버튼을 누르고 전화로 연결됩니다. 통화 취소 후 사용자는 응용 프로그램으로 다시 전송됩니다. 이를 위해서는 버튼에 xml에 onClick 메소드 (이 예제에서는 'makePhoneCall')가 있어야합니다. 또한 매니페스트에 권한을 등록해야합니다.

명백한

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

활동

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

당신은 당신이 말하는 것을조차하지 않습니다. READ_PHONE_STATE-예제 코드에서 사용하지 않는 이유는 무엇입니까? 물론 취소 버튼을 누르면 앱 활동으로 돌아갑니다. 그러나 질문의 ​​작성자는 전화가 수락 된 후 활동으로 돌아가는 방법에 대해 물었습니다
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);
}

5

리스너를 사용하려는 경우 매니페스트에도이 권한을 추가해야합니다.

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

3

호출이 끝난 후 내부 PhoneStateListener가 더 잘 사용됩니다.

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

여기서 CallDispatcherActivity는 사용자가 전화 서비스를 시작한 활동입니다 (필자의 경우 택시 서비스 발송자에게). 이것은 안드로이드 전화 앱을 상단에서 제거하기 때문에 사용자는 내가 본 못생긴 코드 대신 돌아옵니다.


1
전화 통화가 끝난 후 리스너를 제거하는 것을 잊지 마십시오.((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE);
Dmitri Novikov

귀하의 접근 방식을 사용하려고 시도했지만 ControlPanel이라는 활동이 다시 활성화되지 않습니다. 디스플레이에 전화 걸기 인터페이스가 계속 표시되고 ControlPanel의 onResume 및 onNewIntent 진입 점에있는 로거는 완전히 자동입니다. 의도는 다음과 같습니다 Intent intentRestart = new Intent(ControlPanel.this, ControlPanel.class);.. PhoneStateListener도 ControlPanel 내에 있음을 지적해야합니다. 즉, 내 목표는 전화 통화를 시작하기 전의 상태로 UI를 복원하는 것입니다. 어떤 제안?
PeteH

PhoneStateListener 구현 내부에서 로깅을 시도하십시오.
Dmitri Novikov

3

로 돌아가려면 Activity을 들어야합니다 TelephonyStates. 그에 listener당신은 보낼 수 Intent당신을 다시 열려면 Activity전화기가 유휴되면.

적어도 내가 그렇게 할 것입니다.


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

2

다음을 사용하십시오.

finish();

활동의 끝에서. 이전 활동으로 리디렉션됩니다.


2

를 사용하는 경우 호출 후에 수행 할 작업을 트리거 PhoneStateListener하기 위해 PHONE_STATE_IDLE다음 PHONE_STATE_OFFHOOK을 사용해야합니다. 이 표시 될 때 트리거가 발생 PHONE_STATE_IDLE하면 통화 전에 트리거 됩니다. 당신은 상태 변화를 볼 수 있기 때문에PHONE_STATE_IDLE -> PHONE_STATE_OFFHOOK -> PHONE_STATE_IDLE.


진행중인 통화 화면이 열릴 때 앱이 중지되지 않습니까?
lisovaccaro

리스너 객체에 TelephonyManager를 듣고 설정하면 ((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(new PhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE)명시 적으로 중단 할 때까지 휴대 전화 상태를 듣고 활성화 될 것입니다((TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE)).listen(this, LISTEN_NONE)
PonMaran

2

// setonclicklistener에 다음 코드를 입력하십시오.

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

// 매니페스트에서 호출 권한을 부여합니다.

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

1

@Dmitri Novikov FLAG_ACTIVITY_CLEAR_TOP는 새 인스턴스 위에 활성화 된 인스턴스를 지 웁니다. 따라서 프로세스를 완료하기 전에 이전 인스턴스를 종료 할 수 있습니다.



1

단계 :

1) Manifest.xml파일에 필요한 권한을 추가 하십시오.

<!--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) 전화 상태 변경에 대한 리스너를 만듭니다.

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) 당신의 청취자를 초기화하십시오 OnCreate

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

그러나 당신이 당신의 응용 프로그램 마지막 상태를 다시 시작하거나 다시 다시 스택에서 그것을 가지고 싶은 경우 , 다음 교체 FLAG_ACTIVITY_CLEAR_TOP와 함께FLAG_ACTIVITY_SINGLE_TOP

답변 참조



0

전화를 걸면 괜찮아 보입니다.

앱을 앞쪽으로 가져 오는 데는 Android 11 이상과 다운 버전이 다릅니다.

Android 10 이하에서는 새로운 의도, Android 11 이상을 시작해야합니다. BringTaskToFront

통화 상태 유휴 상태에서 :

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

MyActivity.MyActivityTaskId내 활동에서 전화를 걸 때 시간을 설정하면 작동하지 않습니다. 돌아가고 싶은 페이지의 부모 활동 페이지 에서이 변수를 설정하십시오.

MyActivity.MyActivityTaskId = this.getTaskId();

MyActivityTaskId 내 활동 클래스의 정적 변수입니다.

public static int MyActivityTaskId = 0;

이것이 당신에게 도움이되기를 바랍니다. 위 코드를 조금 다르게 사용하면 사용자가 발신자의 세부 정보를 볼 수 있도록 전화가 응답되는 즉시 앱을 엽니 다.

나는 또한 몇 가지를 설정했습니다 AndroidManifest.xml.

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

그리고 권한 :

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

막히면 언제든 질문하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.