Як виявити вхідні дзвінки на пристрої Android?


130

Я намагаюся зробити додаток, як, коли дзвінок надходить на телефон, я хочу виявити номер. Нижче наведено те, що я спробував, але це не виявляє вхідні дзвінки.

Я хочу запустити свій MainActivityфон, як це зробити?

Я дав дозвіл у manifestфайлі.

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

Чи потрібно ще щось вказати в маніфесті?

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

що нам робити для android P
Ахмад Арслан

Відповіді:


336

Ось що я використовую для цього:

Маніфест:

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

Мій базовий детектор викликів для багаторазового використання

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

Потім, щоб використовувати його, просто отримайте клас із нього та реалізуйте кілька простих функцій, залежно від того, які типи викликів вам цікаві:

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)
    {
        //
    }

}

Крім того , ви можете побачити детальніше я зробив про те, чому код, як це в моєму блозі . Посилання на історію: https://gist.github.com/ftvs/e61ccb039f511eb288ee

EDIT: Оновлено до більш простого коду, оскільки я переробив клас для власного використання


2
Цей код нічого не відображає. Що це робить - це зателефонувати вам, коли вихідний дзвінок починається / закінчується, і передає вам номер, початий час та час, що закінчився. Насправді це відображення - це ваша робота, тому що я не можу знати, як ви це робите.
Гейб Сечан

3
@GabeSechan: Дивовижно! Ви можете, будь ласка, направити мене на вирішення ситуації, що чекає дзвінка?
Мехул Джойсар

6
Просто до цього додалося, що це не спрацювало, коли додаток не було на передньому плані чи фоні, поки я не додав це в приймач: "android: enable =" true "
Rajat Sharma

1
Статичні змінні залишатимуться до тих пір, поки додаток не буде вичерпано з пам'яті (що може бути досить довгим, залежно від запуску послуг та загальних умов пам'яті телефону). Але так, вони можуть бути втрачені. Ви можете записати його на диск, скажімо, за допомогою спільних уподобань, але це може призвести до помилкових результатів, і це запобіжить правильному очищенню даних у кількох випадках, наприклад, перезавантаження телефону. У моєму випадку використання рідкісні нульові та втрачені дані були кращими від неправильних. Ви можете поспілкуватися з цим під свої потреби.
Гейб Сечан

1
@GabeSechan: Здається, в цьому помилка. lastState не слід ініціалізувати до CALL_STATE_IDLE. Мені не вистачає декількох дзвінків, коли моя програма вбита, поки це стан RINGING. Тому що, коли він IDLEзнову стає на завершені виклику, статична змінна реініціалізується на CALL_STATE_IDLEі вона деблокує, що нічого не робить. Тож ми втрачаємо посилання на lastState.
Гейзенберг

23
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();

реєструвати

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

і до реєстрації

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

де я повинен використовувати це у майнактичності?
Джесбін MJ

розмістіть це в класі, де ви слухаєте зміни. Зазвичай регістри робляться в oncreate і відреєстрації в ондестрой .. оголошуйте об'єкт у всьому світі в класі
stinepike

Цей параметр не вимагає дозволів.
Майк

в той час як рішення Gabe краще підходить для більш нав'язливих функцій, наприклад, типу програми Viber, це найкраще рішення для тих, хто потребує просто реагувати на дії користувача при вступі на телефонний дзвінок. Запит дозволу на виконання у таких випадках, швидше за все, є надмірним надмірним вмістом, і користувач може не сприймати його добре.
bosphere

1
Я хочу щось зробити, коли надходить дзвінок, як це зробити з цим кодом?
Noor Hossain

14

З Android P - Api 28-го рівня: Вам потрібно отримати дозвіл READ_CALL_LOG

Обмежений доступ до журналів викликів

Android P пересуває CALL_LOG, READ_CALL_LOG, WRITE_CALL_LOGі PROCESS_OUTGOING_CALLSдозвіл від PHONEгрупи дозволів на нове CALL_LOGдозволі групи. Ця група забезпечує користувачам кращий контроль та видимість програм, які потребують доступу до конфіденційної інформації про телефонні дзвінки, наприклад, для читання записів телефонних дзвінків та визначення телефонних номерів.

Щоб прочитати номери з дії наміру PHONE_STATE, вам потрібен і READ_CALL_LOGдозвіл, і READ_PHONE_STATEдозвіл . Щоб читати номери з onCallStateChanged(), вам потрібен лише READ_CALL_LOGдозвіл. Вам більше не потрібен READ_PHONE_STATEдозвіл.


для тих , хто тільки додавши READ_CALL_LOGв AndroidManifest.xmlцентрі уваги на додавання запит на дозвіл в MainActivity.
Піюш

13

ОНОВЛЕННЯ: Дійсно дивовижний код, опублікований Gabe Sechan, більше не працює, якщо ви прямо не попросите користувача надати необхідні дозволи. Ось код, який ви можете розмістити у своїй основній діяльності, щоб запитувати такі дозволи:

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

ТАКОЖ: Як хтось згадав у коментарі під публікацією Gabe , вам потрібно додати трохи осікання коду android:enabled="trueдо приймача, щоб виявити вхідні дзвінки, коли додаток наразі не працює на передньому плані:

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

Що робити, якщо у додатку немає активності, а лише приймач і послуга широкомовної передачі. Тоді куди ми пишемо цей код, щоб отримати дозвіл від користувача, оскільки транслятор прийому не буде викликаний, поки цей дозвіл не буде надано.
користувач2779311

2
Вам потрібен принаймні MainActivity, навіть якщо він відкритий лише один раз. Візьмемо для прикладу додаток для блокування дзвінків RoboStop: Коли користувач завантажує додаток уперше, а потім натискає на піктограму, щоб запустити додаток, їм буде запропоновано надати моєму додатку необхідні дозволи. У додатку також є кнопка, щоб увімкнути / вимкнути блокування викликів, але користувачеві не потрібно запускати додаток / активність знову, блокування дзвінків відбуватиметься у фоновому режимі, без того, щоб користувач знову запускав додаток / діяльність.
topherPedersen

Тим, у кого є проблеми здійснити це, слідкуйте за цим підручником studytutorial.in/…
Prasath

5

це може допомогти вам, а також додати необхідність дозволу

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

2
це здається прекрасним. Але як я можу це використовувати від діяльності? розкажіть, будь ласка, детальніше
Амір

4

Просто для оновлення відповіді Габе Сечан. Якщо ваш маніфест запитує дозволи на READ_CALL_LOG та READ_PHONE_STATE, onReceive буде називатися TWICE . В одному з них EXTRA_INCOMING_NUMBER, а в іншому немає. Ви повинні перевірити, що це має, і це може відбуватися в будь-якому порядку.

https://developer.android.com/reference/android/telephony/TelephonyManager.html#ACTION_PHONE_STATE_CHANGED


2

Ось простий метод, який дозволяє уникнути використання PhonestateListenerта інших ускладнень.
Отже, тут ми отримуємо 3 події від android, таких як RINGING, OFFHOOKі IDLE. І для того , щоб отримати всі можливі стану виклику, ми повинні визначити наші власні стану подобається RINGING, OFFHOOK, IDLE, FIRST_CALL_RINGING, SECOND_CALL_RINGING. Він може обробляти всі штати в телефонному дзвінку.
Будь ласка, подумайте таким чином, що ми отримуємо події від Android, і ми визначимо наші стани дзвінків. Дивіться код.

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

0

@Gabe Sechan, дякую за ваш код. Це добре працює, окрімonOutgoingCallEnded() . Він ніколи не виконується. Тестуючі телефони - Samsung S5 & Trendy. Є 2 помилки, я думаю.

1: пара дужок відсутня.

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;

2: lastStateне оновлюється, stateякщо він знаходиться в кінці функції. Його слід замінити на перший рядок цієї функції на

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;
    }
    //....
}

Додатково я поклав lastStateі savedNumberв загальне перевагу , як ви запропонували.

Просто випробували його з вищезазначеними змінами. Помилка виправлена ​​принаймні на моїх телефонах.


0

Будь ласка, використовуйте наведений нижче код. Це допоможе вам отримати вхідний номер з іншими деталями дзвінків.

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >

<TextView
    android:id="@+id/call"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"
    android:text="@string/hello_world" />

</RelativeLayout>

MainActivity.java

public class MainActivity extends Activity {

private static final int MISSED_CALL_TYPE = 0;
private TextView txtcall;

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

    txtcall = (TextView) findViewById(R.id.call);

    StringBuffer sb = new StringBuffer();
    Cursor managedCursor = managedQuery(CallLog.Calls.CONTENT_URI, null,
            null, null, null);
    int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
    int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
    int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);
    int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
    sb.append("Call Details :");
    while (managedCursor.moveToNext()) {
        String phNumber = managedCursor.getString(number);
        String callType = managedCursor.getString(type);
        String callDate = managedCursor.getString(date);
        Date callDayTime = new Date(Long.valueOf(callDate));
        String callDuration = managedCursor.getString(duration);
        String dir = null;
        int dircode = Integer.parseInt(callType);
        switch (dircode) {

        case CallLog.Calls.OUTGOING_TYPE:
            dir = "OUTGOING";
            break;

        case CallLog.Calls.INCOMING_TYPE:
            dir = "INCOMING";
            break;

        case CallLog.Calls.MISSED_TYPE:
            dir = "MISSED";
            break;
        }
        sb.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- "
                + dir + " \nCall Date:--- " + callDayTime
                + " \nCall duration in sec :--- " + callDuration);
        sb.append("\n----------------------------------");
    }
    managedCursor.close();
    txtcall.setText(sb);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

} 

і у вашому маніфестному запиті щодо таких дозволів:

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

READ_LOGS так що вам забороняється ваш додаток до магазину ігор
Duna

0

Вам потрібен BroadcastReceiver для ACTION_PHONE_STATE_CHANGEDцього. Виклик отриманих повідомлень кожного разу, коли стан телефону зміниться з режиму очікування, дзвінка, відключення, так як попереднє значення та нове значення ви можете виявити, якщо це вхідний / вихідний дзвінок.

Необхідний дозвіл:

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

Але якщо ви також хочете отримати EXTRA_INCOMING_NUMBER у цьому ефірі, вам знадобиться ще один дозвіл: "android.permission.READ_CALL_LOG"

І код приблизно такий:

val receiver: BroadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d(TAG, "onReceive")
    }
}

override fun onResume() {
    val filter = IntentFilter()
    filter.addAction("android.intent.action.PHONE_STATE")
    registerReceiver(receiver, filter)
    super.onResume()
}

override fun onPause() {
    unregisterReceiver(receiver)
    super.onPause()
}

і в класі приймача ми можемо отримати поточний стан, читаючи такі наміри:

intent.extras["state"]

Результатом додаткових можливостей може бути:

ЗВАННЯ -> Якщо телефон дзвонить

OFFHOOK -> Якщо ви спілкуєтесь з ким-небудь (вхідний або вихідний дзвінок)

IDLE -> якщо виклик закінчився (вхідний або вихідний дзвінок)

У режимі трансляції PHONE_STATE нам не потрібно використовувати PROCESS_OUTGOING_CALLS дозвіл або застарілу дію NEW_OUTGOING_CALL.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.