1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony;
18
19import com.android.internal.telephony.sip.SipPhone;
20
21import android.content.Context;
22import android.os.AsyncResult;
23import android.os.Handler;
24import android.os.Message;
25import android.os.RegistrantList;
26import android.os.Registrant;
27import android.telecom.VideoProfile;
28import android.telephony.PhoneNumberUtils;
29import android.telephony.TelephonyManager;
30import android.telephony.PhoneStateListener;
31import android.telephony.ServiceState;
32import android.telephony.Rlog;
33
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.HashMap;
37import java.util.List;
38
39
40
41/**
42 * @hide
43 *
44 * CallManager class provides an abstract layer for PhoneApp to access
45 * and control calls. It implements Phone interface.
46 *
47 * CallManager provides call and connection control as well as
48 * channel capability.
49 *
50 * There are three categories of APIs CallManager provided
51 *
52 *  1. Call control and operation, such as dial() and hangup()
53 *  2. Channel capabilities, such as CanConference()
54 *  3. Register notification
55 *
56 *
57 */
58public class CallManager {
59
60    private static final String LOG_TAG ="CallManager";
61    private static final boolean DBG = true;
62    private static final boolean VDBG = false;
63
64    private static final int EVENT_DISCONNECT = 100;
65    private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101;
66    private static final int EVENT_NEW_RINGING_CONNECTION = 102;
67    private static final int EVENT_UNKNOWN_CONNECTION = 103;
68    private static final int EVENT_INCOMING_RING = 104;
69    private static final int EVENT_RINGBACK_TONE = 105;
70    private static final int EVENT_IN_CALL_VOICE_PRIVACY_ON = 106;
71    private static final int EVENT_IN_CALL_VOICE_PRIVACY_OFF = 107;
72    private static final int EVENT_CALL_WAITING = 108;
73    private static final int EVENT_DISPLAY_INFO = 109;
74    private static final int EVENT_SIGNAL_INFO = 110;
75    private static final int EVENT_CDMA_OTA_STATUS_CHANGE = 111;
76    private static final int EVENT_RESEND_INCALL_MUTE = 112;
77    private static final int EVENT_MMI_INITIATE = 113;
78    private static final int EVENT_MMI_COMPLETE = 114;
79    private static final int EVENT_ECM_TIMER_RESET = 115;
80    private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
81    private static final int EVENT_SUPP_SERVICE_FAILED = 117;
82    private static final int EVENT_SERVICE_STATE_CHANGED = 118;
83    private static final int EVENT_POST_DIAL_CHARACTER = 119;
84    private static final int EVENT_ONHOLD_TONE = 120;
85    // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
86    //private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 121;
87    private static final int EVENT_TTY_MODE_RECEIVED = 122;
88
89    // Singleton instance
90    private static final CallManager INSTANCE = new CallManager();
91
92    // list of registered phones, which are Phone objs
93    private final ArrayList<Phone> mPhones;
94
95    // list of supported ringing calls
96    private final ArrayList<Call> mRingingCalls;
97
98    // list of supported background calls
99    private final ArrayList<Call> mBackgroundCalls;
100
101    // list of supported foreground calls
102    private final ArrayList<Call> mForegroundCalls;
103
104    // empty connection list
105    private final ArrayList<Connection> mEmptyConnections = new ArrayList<Connection>();
106
107    // mapping of phones to registered handler instances used for callbacks from RIL
108    private final HashMap<Phone, CallManagerHandler> mHandlerMap = new HashMap<>();
109
110    // default phone as the first phone registered, which is Phone obj
111    private Phone mDefaultPhone;
112
113    private boolean mSpeedUpAudioForMtCall = false;
114    // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
115    //private boolean mIsEccDialing = false;
116
117    private Object mRegistrantidentifier = new Object();
118
119    // state registrants
120    protected final RegistrantList mPreciseCallStateRegistrants
121    = new RegistrantList();
122
123    protected final RegistrantList mNewRingingConnectionRegistrants
124    = new RegistrantList();
125
126    protected final RegistrantList mIncomingRingRegistrants
127    = new RegistrantList();
128
129    protected final RegistrantList mDisconnectRegistrants
130    = new RegistrantList();
131
132    protected final RegistrantList mMmiRegistrants
133    = new RegistrantList();
134
135    protected final RegistrantList mUnknownConnectionRegistrants
136    = new RegistrantList();
137
138    protected final RegistrantList mRingbackToneRegistrants
139    = new RegistrantList();
140
141    protected final RegistrantList mOnHoldToneRegistrants
142    = new RegistrantList();
143
144    protected final RegistrantList mInCallVoicePrivacyOnRegistrants
145    = new RegistrantList();
146
147    protected final RegistrantList mInCallVoicePrivacyOffRegistrants
148    = new RegistrantList();
149
150    protected final RegistrantList mCallWaitingRegistrants
151    = new RegistrantList();
152
153    protected final RegistrantList mDisplayInfoRegistrants
154    = new RegistrantList();
155
156    protected final RegistrantList mSignalInfoRegistrants
157    = new RegistrantList();
158
159    protected final RegistrantList mCdmaOtaStatusChangeRegistrants
160    = new RegistrantList();
161
162    protected final RegistrantList mResendIncallMuteRegistrants
163    = new RegistrantList();
164
165    protected final RegistrantList mMmiInitiateRegistrants
166    = new RegistrantList();
167
168    protected final RegistrantList mMmiCompleteRegistrants
169    = new RegistrantList();
170
171    protected final RegistrantList mEcmTimerResetRegistrants
172    = new RegistrantList();
173
174    protected final RegistrantList mSubscriptionInfoReadyRegistrants
175    = new RegistrantList();
176
177    protected final RegistrantList mSuppServiceFailedRegistrants
178    = new RegistrantList();
179
180    protected final RegistrantList mServiceStateChangedRegistrants
181    = new RegistrantList();
182
183    protected final RegistrantList mPostDialCharacterRegistrants
184    = new RegistrantList();
185
186    protected final RegistrantList mTtyModeReceivedRegistrants
187    = new RegistrantList();
188
189    private CallManager() {
190        mPhones = new ArrayList<Phone>();
191        mRingingCalls = new ArrayList<Call>();
192        mBackgroundCalls = new ArrayList<Call>();
193        mForegroundCalls = new ArrayList<Call>();
194        mDefaultPhone = null;
195    }
196
197    /**
198     * get singleton instance of CallManager
199     * @return CallManager
200     */
201    public static CallManager getInstance() {
202        return INSTANCE;
203    }
204
205    /**
206     * Returns all the registered phone objects.
207     * @return all the registered phone objects.
208     */
209    public List<Phone> getAllPhones() {
210        return Collections.unmodifiableList(mPhones);
211    }
212
213    /**
214     * get Phone object corresponds to subId
215     * @return Phone
216     */
217    private Phone getPhone(int subId) {
218        Phone p = null;
219        for (Phone phone : mPhones) {
220            if (phone.getSubId() == subId &&
221                    phone.getPhoneType() != PhoneConstants.PHONE_TYPE_IMS) {
222                p = phone;
223                break;
224            }
225        }
226        return p;
227    }
228
229    /**
230     * Get current coarse-grained voice call state.
231     * If the Call Manager has an active call and call waiting occurs,
232     * then the phone state is RINGING not OFFHOOK
233     *
234     */
235    public PhoneConstants.State getState() {
236        PhoneConstants.State s = PhoneConstants.State.IDLE;
237
238        for (Phone phone : mPhones) {
239            if (phone.getState() == PhoneConstants.State.RINGING) {
240                s = PhoneConstants.State.RINGING;
241            } else if (phone.getState() == PhoneConstants.State.OFFHOOK) {
242                if (s == PhoneConstants.State.IDLE) s = PhoneConstants.State.OFFHOOK;
243            }
244        }
245        return s;
246    }
247
248    /**
249     * Get current coarse-grained voice call state on a subId.
250     * If the Call Manager has an active call and call waiting occurs,
251     * then the phone state is RINGING not OFFHOOK
252     *
253     */
254    public PhoneConstants.State getState(int subId) {
255        PhoneConstants.State s = PhoneConstants.State.IDLE;
256
257        for (Phone phone : mPhones) {
258            if (phone.getSubId() == subId) {
259                if (phone.getState() == PhoneConstants.State.RINGING) {
260                    s = PhoneConstants.State.RINGING;
261                } else if (phone.getState() == PhoneConstants.State.OFFHOOK) {
262                    if (s == PhoneConstants.State.IDLE) s = PhoneConstants.State.OFFHOOK;
263                }
264            }
265        }
266        return s;
267    }
268
269    /**
270     * @return the service state of CallManager, which represents the
271     * highest priority state of all the service states of phones
272     *
273     * The priority is defined as
274     *
275     * STATE_IN_SERIVCE > STATE_OUT_OF_SERIVCE > STATE_EMERGENCY > STATE_POWER_OFF
276     *
277     */
278
279    public int getServiceState() {
280        int resultState = ServiceState.STATE_OUT_OF_SERVICE;
281
282        for (Phone phone : mPhones) {
283            int serviceState = phone.getServiceState().getState();
284            if (serviceState == ServiceState.STATE_IN_SERVICE) {
285                // IN_SERVICE has the highest priority
286                resultState = serviceState;
287                break;
288            } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
289                // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
290                // Note: EMERGENCY_ONLY is not in use at this moment
291                if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
292                        resultState == ServiceState.STATE_POWER_OFF) {
293                    resultState = serviceState;
294                }
295            } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
296                if (resultState == ServiceState.STATE_POWER_OFF) {
297                    resultState = serviceState;
298                }
299            }
300        }
301        return resultState;
302    }
303
304    /**
305     * @return the Phone service state corresponds to subId
306     */
307    public int getServiceState(int subId) {
308        int resultState = ServiceState.STATE_OUT_OF_SERVICE;
309
310        for (Phone phone : mPhones) {
311            if (phone.getSubId() == subId) {
312                int serviceState = phone.getServiceState().getState();
313                if (serviceState == ServiceState.STATE_IN_SERVICE) {
314                    // IN_SERVICE has the highest priority
315                    resultState = serviceState;
316                    break;
317                } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
318                    // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
319                    // Note: EMERGENCY_ONLY is not in use at this moment
320                    if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
321                            resultState == ServiceState.STATE_POWER_OFF) {
322                        resultState = serviceState;
323                    }
324                } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
325                    if (resultState == ServiceState.STATE_POWER_OFF) {
326                        resultState = serviceState;
327                    }
328                }
329            }
330        }
331        return resultState;
332    }
333
334    /**
335     * @return the phone associated with any call
336     */
337    public Phone getPhoneInCall() {
338        Phone phone = null;
339        if (!getFirstActiveRingingCall().isIdle()) {
340            phone = getFirstActiveRingingCall().getPhone();
341        } else if (!getActiveFgCall().isIdle()) {
342            phone = getActiveFgCall().getPhone();
343        } else {
344            // If BG call is idle, we return default phone
345            phone = getFirstActiveBgCall().getPhone();
346        }
347        return phone;
348    }
349
350    public Phone getPhoneInCall(int subId) {
351        Phone phone = null;
352        if (!getFirstActiveRingingCall(subId).isIdle()) {
353            phone = getFirstActiveRingingCall(subId).getPhone();
354        } else if (!getActiveFgCall(subId).isIdle()) {
355            phone = getActiveFgCall(subId).getPhone();
356        } else {
357            // If BG call is idle, we return default phone
358            phone = getFirstActiveBgCall(subId).getPhone();
359        }
360        return phone;
361    }
362
363    /**
364     * Register phone to CallManager
365     * @param phone to be registered
366     * @return true if register successfully
367     */
368    public boolean registerPhone(Phone phone) {
369        if (phone != null && !mPhones.contains(phone)) {
370
371            if (DBG) {
372                Rlog.d(LOG_TAG, "registerPhone(" +
373                        phone.getPhoneName() + " " + phone + ")");
374            }
375
376            if (mPhones.isEmpty()) {
377                mDefaultPhone = phone;
378            }
379            mPhones.add(phone);
380            mRingingCalls.add(phone.getRingingCall());
381            mBackgroundCalls.add(phone.getBackgroundCall());
382            mForegroundCalls.add(phone.getForegroundCall());
383            registerForPhoneStates(phone);
384            return true;
385        }
386        return false;
387    }
388
389    /**
390     * unregister phone from CallManager
391     * @param phone to be unregistered
392     */
393    public void unregisterPhone(Phone phone) {
394        if (phone != null && mPhones.contains(phone)) {
395
396            if (DBG) {
397                Rlog.d(LOG_TAG, "unregisterPhone(" +
398                        phone.getPhoneName() + " " + phone + ")");
399            }
400
401            Phone imsPhone = phone.getImsPhone();
402            if (imsPhone != null) {
403                unregisterPhone(imsPhone);
404            }
405
406            mPhones.remove(phone);
407            mRingingCalls.remove(phone.getRingingCall());
408            mBackgroundCalls.remove(phone.getBackgroundCall());
409            mForegroundCalls.remove(phone.getForegroundCall());
410            unregisterForPhoneStates(phone);
411            if (phone == mDefaultPhone) {
412                if (mPhones.isEmpty()) {
413                    mDefaultPhone = null;
414                } else {
415                    mDefaultPhone = mPhones.get(0);
416                }
417            }
418        }
419    }
420
421    /**
422     * return the default phone or null if no phone available
423     */
424    public Phone getDefaultPhone() {
425        return mDefaultPhone;
426    }
427
428    /**
429     * @return the phone associated with the foreground call
430     */
431    public Phone getFgPhone() {
432        return getActiveFgCall().getPhone();
433    }
434
435    /**
436     * @return the phone associated with the foreground call
437     * of a particular subId
438     */
439    public Phone getFgPhone(int subId) {
440        return getActiveFgCall(subId).getPhone();
441    }
442
443    /**
444     * @return the phone associated with the background call
445     */
446    public Phone getBgPhone() {
447        return getFirstActiveBgCall().getPhone();
448    }
449
450    /**
451     * @return the phone associated with the background call
452     * of a particular subId
453     */
454    public Phone getBgPhone(int subId) {
455        return getFirstActiveBgCall(subId).getPhone();
456    }
457
458    /**
459     * @return the phone associated with the ringing call
460     */
461    public Phone getRingingPhone() {
462        return getFirstActiveRingingCall().getPhone();
463    }
464
465    /**
466     * @return the phone associated with the ringing call
467     * of a particular subId
468     */
469    public Phone getRingingPhone(int subId) {
470        return getFirstActiveRingingCall(subId).getPhone();
471    }
472
473    /* FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
474    public void setAudioMode() {
475        Context context = getContext();
476        if (context == null) return;
477        AudioManager audioManager = (AudioManager)
478                context.getSystemService(Context.AUDIO_SERVICE);
479
480        if (!isServiceStateInService() && !mIsEccDialing) {
481            if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
482                if (VDBG) Rlog.d(LOG_TAG, "abandonAudioFocus");
483                // abandon audio focus after the mode has been set back to normal
484                audioManager.abandonAudioFocusForCall();
485                audioManager.setMode(AudioManager.MODE_NORMAL);
486            }
487            return;
488        }
489
490        // change the audio mode and request/abandon audio focus according to phone state,
491        // but only on audio mode transitions
492        switch (getState()) {
493            case RINGING:
494                int curAudioMode = audioManager.getMode();
495                if (curAudioMode != AudioManager.MODE_RINGTONE) {
496                    if (VDBG) Rlog.d(LOG_TAG, "requestAudioFocus on STREAM_RING");
497                    audioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
498                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
499                    if(!mSpeedUpAudioForMtCall) {
500                        audioManager.setMode(AudioManager.MODE_RINGTONE);
501                    }
502                }
503
504                if (mSpeedUpAudioForMtCall && (curAudioMode != AudioManager.MODE_IN_CALL)) {
505                    audioManager.setMode(AudioManager.MODE_IN_CALL);
506                }
507                break;
508            case OFFHOOK:
509                Phone offhookPhone = getFgPhone();
510                if (getActiveFgCallState() == Call.State.IDLE) {
511                    // There is no active Fg calls, the OFFHOOK state
512                    // is set by the Bg call. So set the phone to bgPhone.
513                    offhookPhone = getBgPhone();
514                }
515
516                int newAudioMode = AudioManager.MODE_IN_CALL;
517                if (offhookPhone instanceof SipPhone) {
518                    Rlog.d(LOG_TAG, "setAudioMode Set audio mode for SIP call!");
519                    // enable IN_COMMUNICATION audio mode instead for sipPhone
520                    newAudioMode = AudioManager.MODE_IN_COMMUNICATION;
521                }
522                int currMode = audioManager.getMode();
523                if (currMode != newAudioMode || mSpeedUpAudioForMtCall) {
524                    // request audio focus before setting the new mode
525                    if (VDBG) Rlog.d(LOG_TAG, "requestAudioFocus on STREAM_VOICE_CALL");
526                    audioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
527                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
528                    Rlog.d(LOG_TAG, "setAudioMode Setting audio mode from "
529                            + currMode + " to " + newAudioMode);
530                    audioManager.setMode(newAudioMode);
531                }
532                mSpeedUpAudioForMtCall = false;
533                break;
534            case IDLE:
535                if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
536                    audioManager.setMode(AudioManager.MODE_NORMAL);
537                    if (VDBG) Rlog.d(LOG_TAG, "abandonAudioFocus");
538                    // abandon audio focus after the mode has been set back to normal
539                    audioManager.abandonAudioFocusForCall();
540                }
541                mSpeedUpAudioForMtCall = false;
542                break;
543        }
544        Rlog.d(LOG_TAG, "setAudioMode state = " + getState());
545    }
546    */
547
548    private Context getContext() {
549        Phone defaultPhone = getDefaultPhone();
550        return ((defaultPhone == null) ? null : defaultPhone.getContext());
551    }
552
553    public Object getRegistrantIdentifier() {
554        return mRegistrantidentifier;
555    }
556
557    private void registerForPhoneStates(Phone phone) {
558        // We need to keep a mapping of handler to Phone for proper unregistration.
559        // TODO: Clean up this solution as it is just a work around for each Phone instance
560        // using the same Handler to register with the RIL. When time permits, we should consider
561        // moving the handler (or the reference ot the handler) into the Phone object.
562        // See b/17414427.
563        CallManagerHandler handler = mHandlerMap.get(phone);
564        if (handler != null) {
565            Rlog.d(LOG_TAG, "This phone has already been registered.");
566            return;
567        }
568
569        // New registration, create a new handler instance and register the phone.
570        handler = new CallManagerHandler();
571        mHandlerMap.put(phone, handler);
572
573        // for common events supported by all phones
574        // The mRegistrantIdentifier passed here, is to identify in the Phone
575        // that the registrants are coming from the CallManager.
576        phone.registerForPreciseCallStateChanged(handler, EVENT_PRECISE_CALL_STATE_CHANGED,
577                mRegistrantidentifier);
578        phone.registerForDisconnect(handler, EVENT_DISCONNECT,
579                mRegistrantidentifier);
580        phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION,
581                mRegistrantidentifier);
582        phone.registerForUnknownConnection(handler, EVENT_UNKNOWN_CONNECTION,
583                mRegistrantidentifier);
584        phone.registerForIncomingRing(handler, EVENT_INCOMING_RING,
585                mRegistrantidentifier);
586        phone.registerForRingbackTone(handler, EVENT_RINGBACK_TONE,
587                mRegistrantidentifier);
588        phone.registerForInCallVoicePrivacyOn(handler, EVENT_IN_CALL_VOICE_PRIVACY_ON,
589                mRegistrantidentifier);
590        phone.registerForInCallVoicePrivacyOff(handler, EVENT_IN_CALL_VOICE_PRIVACY_OFF,
591                mRegistrantidentifier);
592        phone.registerForDisplayInfo(handler, EVENT_DISPLAY_INFO,
593                mRegistrantidentifier);
594        phone.registerForSignalInfo(handler, EVENT_SIGNAL_INFO,
595                mRegistrantidentifier);
596        phone.registerForResendIncallMute(handler, EVENT_RESEND_INCALL_MUTE,
597                mRegistrantidentifier);
598        phone.registerForMmiInitiate(handler, EVENT_MMI_INITIATE,
599                mRegistrantidentifier);
600        phone.registerForMmiComplete(handler, EVENT_MMI_COMPLETE,
601                mRegistrantidentifier);
602        phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED,
603                mRegistrantidentifier);
604        phone.registerForServiceStateChanged(handler, EVENT_SERVICE_STATE_CHANGED,
605                mRegistrantidentifier);
606
607        // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
608        //phone.registerForRadioOffOrNotAvailable(handler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
609
610        // for events supported only by GSM, CDMA and IMS phone
611        phone.setOnPostDialCharacter(handler, EVENT_POST_DIAL_CHARACTER, null);
612
613        // for events supported only by CDMA phone
614        phone.registerForCdmaOtaStatusChange(handler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
615        phone.registerForSubscriptionInfoReady(handler, EVENT_SUBSCRIPTION_INFO_READY, null);
616        phone.registerForCallWaiting(handler, EVENT_CALL_WAITING, null);
617        phone.registerForEcmTimerReset(handler, EVENT_ECM_TIMER_RESET, null);
618
619        // for events supported only by IMS phone
620        phone.registerForOnHoldTone(handler, EVENT_ONHOLD_TONE, null);
621        phone.registerForSuppServiceFailed(handler, EVENT_SUPP_SERVICE_FAILED, null);
622        phone.registerForTtyModeReceived(handler, EVENT_TTY_MODE_RECEIVED, null);
623    }
624
625    private void unregisterForPhoneStates(Phone phone) {
626        // Make sure that we clean up our map of handlers to Phones.
627        CallManagerHandler handler = mHandlerMap.get(phone);
628        if (handler == null) {
629            Rlog.e(LOG_TAG, "Could not find Phone handler for unregistration");
630            return;
631        }
632        mHandlerMap.remove(phone);
633
634        //  for common events supported by all phones
635        phone.unregisterForPreciseCallStateChanged(handler);
636        phone.unregisterForDisconnect(handler);
637        phone.unregisterForNewRingingConnection(handler);
638        phone.unregisterForUnknownConnection(handler);
639        phone.unregisterForIncomingRing(handler);
640        phone.unregisterForRingbackTone(handler);
641        phone.unregisterForInCallVoicePrivacyOn(handler);
642        phone.unregisterForInCallVoicePrivacyOff(handler);
643        phone.unregisterForDisplayInfo(handler);
644        phone.unregisterForSignalInfo(handler);
645        phone.unregisterForResendIncallMute(handler);
646        phone.unregisterForMmiInitiate(handler);
647        phone.unregisterForMmiComplete(handler);
648        phone.unregisterForSuppServiceFailed(handler);
649        phone.unregisterForServiceStateChanged(handler);
650        phone.unregisterForTtyModeReceived(handler);
651        // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
652        //phone.unregisterForRadioOffOrNotAvailable(handler);
653
654        // for events supported only by GSM, CDMA and IMS phone
655        phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
656
657        // for events supported only by CDMA phone
658        phone.unregisterForCdmaOtaStatusChange(handler);
659        phone.unregisterForSubscriptionInfoReady(handler);
660        phone.unregisterForCallWaiting(handler);
661        phone.unregisterForEcmTimerReset(handler);
662
663        // for events supported only by IMS phone
664        phone.unregisterForOnHoldTone(handler);
665        phone.unregisterForSuppServiceFailed(handler);
666    }
667
668    /**
669     * Answers a ringing or waiting call.
670     *
671     * Active call, if any, go on hold.
672     * If active call can't be held, i.e., a background call of the same channel exists,
673     * the active call will be hang up.
674     *
675     * Answering occurs asynchronously, and final notification occurs via
676     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
677     * java.lang.Object) registerForPreciseCallStateChanged()}.
678     *
679     * @exception CallStateException when call is not ringing or waiting
680     */
681    public void acceptCall(Call ringingCall) throws CallStateException {
682        Phone ringingPhone = ringingCall.getPhone();
683
684        if (VDBG) {
685            Rlog.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")");
686            Rlog.d(LOG_TAG, toString());
687        }
688
689        if ( hasActiveFgCall() ) {
690            Phone activePhone = getActiveFgCall().getPhone();
691            boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
692            boolean sameChannel = (activePhone == ringingPhone);
693
694            if (VDBG) {
695                Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
696            }
697
698            if (sameChannel && hasBgCall) {
699                getActiveFgCall().hangup();
700            } else if (!sameChannel && !hasBgCall) {
701                activePhone.switchHoldingAndActive();
702            } else if (!sameChannel && hasBgCall) {
703                getActiveFgCall().hangup();
704            }
705        }
706
707        // We only support the AUDIO_ONLY video state in this scenario.
708        ringingPhone.acceptCall(VideoProfile.STATE_AUDIO_ONLY);
709
710        if (VDBG) {
711            Rlog.d(LOG_TAG, "End acceptCall(" +ringingCall + ")");
712            Rlog.d(LOG_TAG, toString());
713        }
714    }
715
716    /**
717     * Reject (ignore) a ringing call. In GSM, this means UDUB
718     * (User Determined User Busy). Reject occurs asynchronously,
719     * and final notification occurs via
720     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
721     * java.lang.Object) registerForPreciseCallStateChanged()}.
722     *
723     * @exception CallStateException when no call is ringing or waiting
724     */
725    public void rejectCall(Call ringingCall) throws CallStateException {
726        if (VDBG) {
727            Rlog.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
728            Rlog.d(LOG_TAG, toString());
729        }
730
731        Phone ringingPhone = ringingCall.getPhone();
732
733        ringingPhone.rejectCall();
734
735        if (VDBG) {
736            Rlog.d(LOG_TAG, "End rejectCall(" +ringingCall + ")");
737            Rlog.d(LOG_TAG, toString());
738        }
739    }
740
741    /**
742     * Places active call on hold, and makes held call active.
743     * Switch occurs asynchronously and may fail.
744     *
745     * There are 4 scenarios
746     * 1. only active call but no held call, aka, hold
747     * 2. no active call but only held call, aka, unhold
748     * 3. both active and held calls from same phone, aka, swap
749     * 4. active and held calls from different phones, aka, phone swap
750     *
751     * Final notification occurs via
752     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
753     * java.lang.Object) registerForPreciseCallStateChanged()}.
754     *
755     * @exception CallStateException if active call is ringing, waiting, or
756     * dialing/alerting, or heldCall can't be active.
757     * In these cases, this operation may not be performed.
758     */
759    public void switchHoldingAndActive(Call heldCall) throws CallStateException {
760        Phone activePhone = null;
761        Phone heldPhone = null;
762
763        if (VDBG) {
764            Rlog.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")");
765            Rlog.d(LOG_TAG, toString());
766        }
767
768        if (hasActiveFgCall()) {
769            activePhone = getActiveFgCall().getPhone();
770        }
771
772        if (heldCall != null) {
773            heldPhone = heldCall.getPhone();
774        }
775
776        if (activePhone != null) {
777            activePhone.switchHoldingAndActive();
778        }
779
780        if (heldPhone != null && heldPhone != activePhone) {
781            heldPhone.switchHoldingAndActive();
782        }
783
784        if (VDBG) {
785            Rlog.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")");
786            Rlog.d(LOG_TAG, toString());
787        }
788    }
789
790    /**
791     * Hangup foreground call and resume the specific background call
792     *
793     * Note: this is noop if there is no foreground call or the heldCall is null
794     *
795     * @param heldCall to become foreground
796     * @throws CallStateException
797     */
798    public void hangupForegroundResumeBackground(Call heldCall) throws CallStateException {
799        Phone foregroundPhone = null;
800        Phone backgroundPhone = null;
801
802        if (VDBG) {
803            Rlog.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")");
804            Rlog.d(LOG_TAG, toString());
805        }
806
807        if (hasActiveFgCall()) {
808            foregroundPhone = getFgPhone();
809            if (heldCall != null) {
810                backgroundPhone = heldCall.getPhone();
811                if (foregroundPhone == backgroundPhone) {
812                    getActiveFgCall().hangup();
813                } else {
814                // the call to be hangup and resumed belongs to different phones
815                    getActiveFgCall().hangup();
816                    switchHoldingAndActive(heldCall);
817                }
818            }
819        }
820
821        if (VDBG) {
822            Rlog.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")");
823            Rlog.d(LOG_TAG, toString());
824        }
825    }
826
827    /**
828     * Whether or not the phone can conference in the current phone
829     * state--that is, one call holding and one call active.
830     * @return true if the phone can conference; false otherwise.
831     */
832    public boolean canConference(Call heldCall) {
833        Phone activePhone = null;
834        Phone heldPhone = null;
835
836        if (hasActiveFgCall()) {
837            activePhone = getActiveFgCall().getPhone();
838        }
839
840        if (heldCall != null) {
841            heldPhone = heldCall.getPhone();
842        }
843
844        return heldPhone.getClass().equals(activePhone.getClass());
845    }
846
847    /**
848     * Whether or not the phone can conference in the current phone
849     * state--that is, one call holding and one call active.
850     * This method consider the phone object which is specific
851     * to the provided subId.
852     * @return true if the phone can conference; false otherwise.
853     */
854    public boolean canConference(Call heldCall, int subId) {
855        Phone activePhone = null;
856        Phone heldPhone = null;
857
858        if (hasActiveFgCall(subId)) {
859            activePhone = getActiveFgCall(subId).getPhone();
860        }
861
862        if (heldCall != null) {
863            heldPhone = heldCall.getPhone();
864        }
865
866        return heldPhone.getClass().equals(activePhone.getClass());
867    }
868
869    /**
870     * Conferences holding and active. Conference occurs asynchronously
871     * and may fail. Final notification occurs via
872     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
873     * java.lang.Object) registerForPreciseCallStateChanged()}.
874     *
875     * @exception CallStateException if canConference() would return false.
876     * In these cases, this operation may not be performed.
877     */
878    public void conference(Call heldCall) throws CallStateException {
879        int subId  = heldCall.getPhone().getSubId();
880
881        if (VDBG) {
882            Rlog.d(LOG_TAG, "conference(" +heldCall + ")");
883            Rlog.d(LOG_TAG, toString());
884        }
885
886        Phone fgPhone = getFgPhone(subId);
887        if (fgPhone != null) {
888            if (fgPhone instanceof SipPhone) {
889                ((SipPhone) fgPhone).conference(heldCall);
890            } else if (canConference(heldCall)) {
891                fgPhone.conference();
892            } else {
893                throw(new CallStateException("Can't conference foreground and selected background call"));
894            }
895        } else {
896            Rlog.d(LOG_TAG, "conference: fgPhone=null");
897        }
898
899        if (VDBG) {
900            Rlog.d(LOG_TAG, "End conference(" +heldCall + ")");
901            Rlog.d(LOG_TAG, toString());
902        }
903
904    }
905
906    /**
907     * Initiate a new voice connection. This happens asynchronously, so you
908     * cannot assume the audio path is connected (or a call index has been
909     * assigned) until PhoneStateChanged notification has occurred.
910     *
911     * @exception CallStateException if a new outgoing call is not currently
912     * possible because no more call slots exist or a call exists that is
913     * dialing, alerting, ringing, or waiting.  Other errors are
914     * handled asynchronously.
915     */
916    public Connection dial(Phone phone, String dialString, int videoState)
917            throws CallStateException {
918        int subId = phone.getSubId();
919        Connection result;
920
921        if (VDBG) {
922            Rlog.d(LOG_TAG, " dial(" + phone + ", "+ dialString + ")" +
923                    " subId = " + subId);
924            Rlog.d(LOG_TAG, toString());
925        }
926
927        if (!canDial(phone)) {
928            /*
929             * canDial function only checks whether the phone can make a new call.
930             * InCall MMI commmands are basically supplementary services
931             * within a call eg: call hold, call deflection, explicit call transfer etc.
932             */
933            String newDialString = PhoneNumberUtils.stripSeparators(dialString);
934            if (phone.handleInCallMmiCommands(newDialString)) {
935                return null;
936            } else {
937                throw new CallStateException("cannot dial in current state");
938            }
939        }
940
941        if ( hasActiveFgCall(subId) ) {
942            Phone activePhone = getActiveFgCall(subId).getPhone();
943            boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
944
945            if (DBG) {
946                Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == phone));
947            }
948
949            // Manipulation between IMS phone and its owner
950            // will be treated in GSM/CDMA phone.
951            Phone imsPhone = phone.getImsPhone();
952            if (activePhone != phone
953                    && (imsPhone == null || imsPhone != activePhone)) {
954                if (hasBgCall) {
955                    Rlog.d(LOG_TAG, "Hangup");
956                    getActiveFgCall(subId).hangup();
957                } else {
958                    Rlog.d(LOG_TAG, "Switch");
959                    activePhone.switchHoldingAndActive();
960                }
961            }
962        }
963
964        // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
965        //mIsEccDialing = PhoneNumberUtils.isEmergencyNumber(dialString);
966
967        result = phone.dial(dialString, videoState);
968
969        if (VDBG) {
970            Rlog.d(LOG_TAG, "End dial(" + phone + ", "+ dialString + ")");
971            Rlog.d(LOG_TAG, toString());
972        }
973
974        return result;
975    }
976
977    /**
978     * Initiate a new voice connection. This happens asynchronously, so you
979     * cannot assume the audio path is connected (or a call index has been
980     * assigned) until PhoneStateChanged notification has occurred.
981     *
982     * @exception CallStateException if a new outgoing call is not currently
983     * possible because no more call slots exist or a call exists that is
984     * dialing, alerting, ringing, or waiting.  Other errors are
985     * handled asynchronously.
986     */
987    public Connection dial(Phone phone, String dialString, UUSInfo uusInfo, int videoState)
988            throws CallStateException {
989        return phone.dial(dialString, uusInfo, videoState, null);
990    }
991
992    /**
993     * clear disconnect connection for each phone
994     */
995    public void clearDisconnected() {
996        for(Phone phone : mPhones) {
997            phone.clearDisconnected();
998        }
999    }
1000
1001    /**
1002     * clear disconnect connection for a phone specific
1003     * to the provided subId
1004     */
1005    public void clearDisconnected(int subId) {
1006        for(Phone phone : mPhones) {
1007            if (phone.getSubId() == subId) {
1008                phone.clearDisconnected();
1009            }
1010        }
1011    }
1012
1013    /**
1014     * Phone can make a call only if ALL of the following are true:
1015     *        - Phone is not powered off
1016     *        - There's no incoming or waiting call
1017     *        - The foreground call is ACTIVE or IDLE or DISCONNECTED.
1018     *          (We mainly need to make sure it *isn't* DIALING or ALERTING.)
1019     * @param phone
1020     * @return true if the phone can make a new call
1021     */
1022    private boolean canDial(Phone phone) {
1023        int serviceState = phone.getServiceState().getState();
1024        int subId = phone.getSubId();
1025        boolean hasRingingCall = hasActiveRingingCall();
1026        Call.State fgCallState = getActiveFgCallState(subId);
1027
1028        boolean result = (serviceState != ServiceState.STATE_POWER_OFF
1029                && !hasRingingCall
1030                && ((fgCallState == Call.State.ACTIVE)
1031                    || (fgCallState == Call.State.IDLE)
1032                    || (fgCallState == Call.State.DISCONNECTED)
1033                    /*As per 3GPP TS 51.010-1 section 31.13.1.4
1034                    call should be alowed when the foreground
1035                    call is in ALERTING state*/
1036                    || (fgCallState == Call.State.ALERTING)));
1037
1038        if (result == false) {
1039            Rlog.d(LOG_TAG, "canDial serviceState=" + serviceState
1040                            + " hasRingingCall=" + hasRingingCall
1041                            + " fgCallState=" + fgCallState);
1042        }
1043        return result;
1044    }
1045
1046    /**
1047     * Whether or not the phone can do explicit call transfer in the current
1048     * phone state--that is, one call holding and one call active.
1049     * @return true if the phone can do explicit call transfer; false otherwise.
1050     */
1051    public boolean canTransfer(Call heldCall) {
1052        Phone activePhone = null;
1053        Phone heldPhone = null;
1054
1055        if (hasActiveFgCall()) {
1056            activePhone = getActiveFgCall().getPhone();
1057        }
1058
1059        if (heldCall != null) {
1060            heldPhone = heldCall.getPhone();
1061        }
1062
1063        return (heldPhone == activePhone && activePhone.canTransfer());
1064    }
1065
1066    /**
1067     * Whether or not the phone specific to subId can do explicit call transfer
1068     * in the current phone state--that is, one call holding and one call active.
1069     * @return true if the phone can do explicit call transfer; false otherwise.
1070     */
1071    public boolean canTransfer(Call heldCall, int subId) {
1072        Phone activePhone = null;
1073        Phone heldPhone = null;
1074
1075        if (hasActiveFgCall(subId)) {
1076            activePhone = getActiveFgCall(subId).getPhone();
1077        }
1078
1079        if (heldCall != null) {
1080            heldPhone = heldCall.getPhone();
1081        }
1082
1083        return (heldPhone == activePhone && activePhone.canTransfer());
1084    }
1085
1086    /**
1087     * Connects the held call and active call
1088     * Disconnects the subscriber from both calls
1089     *
1090     * Explicit Call Transfer occurs asynchronously
1091     * and may fail. Final notification occurs via
1092     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
1093     * java.lang.Object) registerForPreciseCallStateChanged()}.
1094     *
1095     * @exception CallStateException if canTransfer() would return false.
1096     * In these cases, this operation may not be performed.
1097     */
1098    public void explicitCallTransfer(Call heldCall) throws CallStateException {
1099        if (VDBG) {
1100            Rlog.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")");
1101            Rlog.d(LOG_TAG, toString());
1102        }
1103
1104        if (canTransfer(heldCall)) {
1105            heldCall.getPhone().explicitCallTransfer();
1106        }
1107
1108        if (VDBG) {
1109            Rlog.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")");
1110            Rlog.d(LOG_TAG, toString());
1111        }
1112
1113    }
1114
1115    /**
1116     * Returns a list of MMI codes that are pending for a phone. (They have initiated
1117     * but have not yet completed).
1118     * Presently there is only ever one.
1119     *
1120     * Use <code>registerForMmiInitiate</code>
1121     * and <code>registerForMmiComplete</code> for change notification.
1122     * @return null if phone doesn't have or support mmi code
1123     */
1124    public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
1125        Rlog.e(LOG_TAG, "getPendingMmiCodes not implemented");
1126        return null;
1127    }
1128
1129    /**
1130     * Sends user response to a USSD REQUEST message.  An MmiCode instance
1131     * representing this response is sent to handlers registered with
1132     * registerForMmiInitiate.
1133     *
1134     * @param ussdMessge    Message to send in the response.
1135     * @return false if phone doesn't support ussd service
1136     */
1137    public boolean sendUssdResponse(Phone phone, String ussdMessge) {
1138        Rlog.e(LOG_TAG, "sendUssdResponse not implemented");
1139        return false;
1140    }
1141
1142    /**
1143     * Mutes or unmutes the microphone for the active call. The microphone
1144     * is automatically unmuted if a call is answered, dialed, or resumed
1145     * from a holding state.
1146     *
1147     * @param muted true to mute the microphone,
1148     * false to activate the microphone.
1149     */
1150
1151    public void setMute(boolean muted) {
1152        if (VDBG) {
1153            Rlog.d(LOG_TAG, " setMute(" + muted + ")");
1154            Rlog.d(LOG_TAG, toString());
1155        }
1156
1157        if (hasActiveFgCall()) {
1158            getActiveFgCall().getPhone().setMute(muted);
1159        }
1160
1161        if (VDBG) {
1162            Rlog.d(LOG_TAG, "End setMute(" + muted + ")");
1163            Rlog.d(LOG_TAG, toString());
1164        }
1165    }
1166
1167    /**
1168     * Gets current mute status. Use
1169     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
1170     * java.lang.Object) registerForPreciseCallStateChanged()}
1171     * as a change notifcation, although presently phone state changed is not
1172     * fired when setMute() is called.
1173     *
1174     * @return true is muting, false is unmuting
1175     */
1176    public boolean getMute() {
1177        if (hasActiveFgCall()) {
1178            return getActiveFgCall().getPhone().getMute();
1179        } else if (hasActiveBgCall()) {
1180            return getFirstActiveBgCall().getPhone().getMute();
1181        }
1182        return false;
1183    }
1184
1185    /**
1186     * Enables or disables echo suppression.
1187     */
1188    public void setEchoSuppressionEnabled() {
1189        if (VDBG) {
1190            Rlog.d(LOG_TAG, " setEchoSuppression()");
1191            Rlog.d(LOG_TAG, toString());
1192        }
1193
1194        if (hasActiveFgCall()) {
1195            getActiveFgCall().getPhone().setEchoSuppressionEnabled();
1196        }
1197
1198        if (VDBG) {
1199            Rlog.d(LOG_TAG, "End setEchoSuppression()");
1200            Rlog.d(LOG_TAG, toString());
1201        }
1202    }
1203
1204    /**
1205     * Play a DTMF tone on the active call.
1206     *
1207     * @param c should be one of 0-9, '*' or '#'. Other values will be
1208     * silently ignored.
1209     * @return false if no active call or the active call doesn't support
1210     *         dtmf tone
1211     */
1212    public boolean sendDtmf(char c) {
1213        boolean result = false;
1214
1215        if (VDBG) {
1216            Rlog.d(LOG_TAG, " sendDtmf(" + c + ")");
1217            Rlog.d(LOG_TAG, toString());
1218        }
1219
1220        if (hasActiveFgCall()) {
1221            getActiveFgCall().getPhone().sendDtmf(c);
1222            result = true;
1223        }
1224
1225        if (VDBG) {
1226            Rlog.d(LOG_TAG, "End sendDtmf(" + c + ")");
1227            Rlog.d(LOG_TAG, toString());
1228        }
1229        return result;
1230    }
1231
1232    /**
1233     * Start to paly a DTMF tone on the active call.
1234     * or there is a playing DTMF tone.
1235     * @param c should be one of 0-9, '*' or '#'. Other values will be
1236     * silently ignored.
1237     *
1238     * @return false if no active call or the active call doesn't support
1239     *         dtmf tone
1240     */
1241    public boolean startDtmf(char c) {
1242        boolean result = false;
1243
1244        if (VDBG) {
1245            Rlog.d(LOG_TAG, " startDtmf(" + c + ")");
1246            Rlog.d(LOG_TAG, toString());
1247        }
1248
1249        if (hasActiveFgCall()) {
1250            getActiveFgCall().getPhone().startDtmf(c);
1251            result = true;
1252        }
1253
1254        if (VDBG) {
1255            Rlog.d(LOG_TAG, "End startDtmf(" + c + ")");
1256            Rlog.d(LOG_TAG, toString());
1257        }
1258
1259        return result;
1260    }
1261
1262    /**
1263     * Stop the playing DTMF tone. Ignored if there is no playing DTMF
1264     * tone or no active call.
1265     */
1266    public void stopDtmf() {
1267        if (VDBG) {
1268            Rlog.d(LOG_TAG, " stopDtmf()" );
1269            Rlog.d(LOG_TAG, toString());
1270        }
1271
1272        if (hasActiveFgCall()) getFgPhone().stopDtmf();
1273
1274        if (VDBG) {
1275            Rlog.d(LOG_TAG, "End stopDtmf()");
1276            Rlog.d(LOG_TAG, toString());
1277        }
1278    }
1279
1280    /**
1281     * send burst DTMF tone, it can send the string as single character or multiple character
1282     * ignore if there is no active call or not valid digits string.
1283     * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
1284     * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
1285     * this api can send single character and multiple character, also, this api has response
1286     * back to caller.
1287     *
1288     * @param dtmfString is string representing the dialing digit(s) in the active call
1289     * @param on the DTMF ON length in milliseconds, or 0 for default
1290     * @param off the DTMF OFF length in milliseconds, or 0 for default
1291     * @param onComplete is the callback message when the action is processed by BP
1292     *
1293     */
1294    public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1295        if (hasActiveFgCall()) {
1296            getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
1297            return true;
1298        }
1299        return false;
1300    }
1301
1302    /**
1303     * Notifies when a voice connection has disconnected, either due to local
1304     * or remote hangup or error.
1305     *
1306     *  Messages received from this will have the following members:<p>
1307     *  <ul><li>Message.obj will be an AsyncResult</li>
1308     *  <li>AsyncResult.userObj = obj</li>
1309     *  <li>AsyncResult.result = a Connection object that is
1310     *  no longer connected.</li></ul>
1311     */
1312    public void registerForDisconnect(Handler h, int what, Object obj) {
1313        mDisconnectRegistrants.addUnique(h, what, obj);
1314    }
1315
1316    /**
1317     * Unregisters for voice disconnection notification.
1318     * Extraneous calls are tolerated silently
1319     */
1320    public void unregisterForDisconnect(Handler h){
1321        mDisconnectRegistrants.remove(h);
1322    }
1323
1324    /**
1325     * Register for getting notifications for change in the Call State {@link Call.State}
1326     * This is called PreciseCallState because the call state is more precise than what
1327     * can be obtained using the {@link PhoneStateListener}
1328     *
1329     * Resulting events will have an AsyncResult in <code>Message.obj</code>.
1330     * AsyncResult.userData will be set to the obj argument here.
1331     * The <em>h</em> parameter is held only by a weak reference.
1332     */
1333    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
1334        mPreciseCallStateRegistrants.addUnique(h, what, obj);
1335    }
1336
1337    /**
1338     * Unregisters for voice call state change notifications.
1339     * Extraneous calls are tolerated silently.
1340     */
1341    public void unregisterForPreciseCallStateChanged(Handler h){
1342        mPreciseCallStateRegistrants.remove(h);
1343    }
1344
1345    /**
1346     * Notifies when a previously untracked non-ringing/waiting connection has appeared.
1347     * This is likely due to some other entity (eg, SIM card application) initiating a call.
1348     */
1349    public void registerForUnknownConnection(Handler h, int what, Object obj){
1350        mUnknownConnectionRegistrants.addUnique(h, what, obj);
1351    }
1352
1353    /**
1354     * Unregisters for unknown connection notifications.
1355     */
1356    public void unregisterForUnknownConnection(Handler h){
1357        mUnknownConnectionRegistrants.remove(h);
1358    }
1359
1360
1361    /**
1362     * Notifies when a new ringing or waiting connection has appeared.<p>
1363     *
1364     *  Messages received from this:
1365     *  Message.obj will be an AsyncResult
1366     *  AsyncResult.userObj = obj
1367     *  AsyncResult.result = a Connection. <p>
1368     *  Please check Connection.isRinging() to make sure the Connection
1369     *  has not dropped since this message was posted.
1370     *  If Connection.isRinging() is true, then
1371     *   Connection.getCall() == Phone.getRingingCall()
1372     */
1373    public void registerForNewRingingConnection(Handler h, int what, Object obj){
1374        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
1375    }
1376
1377    /**
1378     * Unregisters for new ringing connection notification.
1379     * Extraneous calls are tolerated silently
1380     */
1381
1382    public void unregisterForNewRingingConnection(Handler h){
1383        mNewRingingConnectionRegistrants.remove(h);
1384    }
1385
1386    /**
1387     * Notifies when an incoming call rings.<p>
1388     *
1389     *  Messages received from this:
1390     *  Message.obj will be an AsyncResult
1391     *  AsyncResult.userObj = obj
1392     *  AsyncResult.result = a Connection. <p>
1393     */
1394    public void registerForIncomingRing(Handler h, int what, Object obj){
1395        mIncomingRingRegistrants.addUnique(h, what, obj);
1396    }
1397
1398    /**
1399     * Unregisters for ring notification.
1400     * Extraneous calls are tolerated silently
1401     */
1402
1403    public void unregisterForIncomingRing(Handler h){
1404        mIncomingRingRegistrants.remove(h);
1405    }
1406
1407    /**
1408     * Notifies when out-band ringback tone is needed.<p>
1409     *
1410     *  Messages received from this:
1411     *  Message.obj will be an AsyncResult
1412     *  AsyncResult.userObj = obj
1413     *  AsyncResult.result = boolean, true to start play ringback tone
1414     *                       and false to stop. <p>
1415     */
1416    public void registerForRingbackTone(Handler h, int what, Object obj){
1417        mRingbackToneRegistrants.addUnique(h, what, obj);
1418    }
1419
1420    /**
1421     * Unregisters for ringback tone notification.
1422     */
1423
1424    public void unregisterForRingbackTone(Handler h){
1425        mRingbackToneRegistrants.remove(h);
1426    }
1427
1428    /**
1429     * Notifies when out-band on-hold tone is needed.<p>
1430     *
1431     *  Messages received from this:
1432     *  Message.obj will be an AsyncResult
1433     *  AsyncResult.userObj = obj
1434     *  AsyncResult.result = boolean, true to start play on-hold tone
1435     *                       and false to stop. <p>
1436     */
1437    public void registerForOnHoldTone(Handler h, int what, Object obj){
1438        mOnHoldToneRegistrants.addUnique(h, what, obj);
1439    }
1440
1441    /**
1442     * Unregisters for on-hold tone notification.
1443     */
1444
1445    public void unregisterForOnHoldTone(Handler h){
1446        mOnHoldToneRegistrants.remove(h);
1447    }
1448
1449    /**
1450     * Registers the handler to reset the uplink mute state to get
1451     * uplink audio.
1452     */
1453    public void registerForResendIncallMute(Handler h, int what, Object obj){
1454        mResendIncallMuteRegistrants.addUnique(h, what, obj);
1455    }
1456
1457    /**
1458     * Unregisters for resend incall mute notifications.
1459     */
1460    public void unregisterForResendIncallMute(Handler h){
1461        mResendIncallMuteRegistrants.remove(h);
1462    }
1463
1464    /**
1465     * Register for notifications of initiation of a new MMI code request.
1466     * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
1467     *
1468     * Example: If Phone.dial is called with "*#31#", then the app will
1469     * be notified here.<p>
1470     *
1471     * The returned <code>Message.obj</code> will contain an AsyncResult.
1472     *
1473     * <code>obj.result</code> will be an "MmiCode" object.
1474     */
1475    public void registerForMmiInitiate(Handler h, int what, Object obj){
1476        mMmiInitiateRegistrants.addUnique(h, what, obj);
1477    }
1478
1479    /**
1480     * Unregisters for new MMI initiate notification.
1481     * Extraneous calls are tolerated silently
1482     */
1483    public void unregisterForMmiInitiate(Handler h){
1484        mMmiInitiateRegistrants.remove(h);
1485    }
1486
1487    /**
1488     * Register for notifications that an MMI request has completed
1489     * its network activity and is in its final state. This may mean a state
1490     * of COMPLETE, FAILED, or CANCELLED.
1491     *
1492     * <code>Message.obj</code> will contain an AsyncResult.
1493     * <code>obj.result</code> will be an "MmiCode" object
1494     */
1495    public void registerForMmiComplete(Handler h, int what, Object obj){
1496        mMmiCompleteRegistrants.addUnique(h, what, obj);
1497    }
1498
1499    /**
1500     * Unregisters for MMI complete notification.
1501     * Extraneous calls are tolerated silently
1502     */
1503    public void unregisterForMmiComplete(Handler h){
1504        mMmiCompleteRegistrants.remove(h);
1505    }
1506
1507    /**
1508     * Registration point for Ecm timer reset
1509     * @param h handler to notify
1510     * @param what user-defined message code
1511     * @param obj placed in Message.obj
1512     */
1513    public void registerForEcmTimerReset(Handler h, int what, Object obj){
1514        mEcmTimerResetRegistrants.addUnique(h, what, obj);
1515    }
1516
1517    /**
1518     * Unregister for notification for Ecm timer reset
1519     * @param h Handler to be removed from the registrant list.
1520     */
1521    public void unregisterForEcmTimerReset(Handler h){
1522        mEcmTimerResetRegistrants.remove(h);
1523    }
1524
1525    /**
1526     * Register for ServiceState changed.
1527     * Message.obj will contain an AsyncResult.
1528     * AsyncResult.result will be a ServiceState instance
1529     */
1530    public void registerForServiceStateChanged(Handler h, int what, Object obj){
1531        mServiceStateChangedRegistrants.addUnique(h, what, obj);
1532    }
1533
1534    /**
1535     * Unregisters for ServiceStateChange notification.
1536     * Extraneous calls are tolerated silently
1537     */
1538    public void unregisterForServiceStateChanged(Handler h){
1539        mServiceStateChangedRegistrants.remove(h);
1540    }
1541
1542    /**
1543     * Register for notifications when a supplementary service attempt fails.
1544     * Message.obj will contain an AsyncResult.
1545     *
1546     * @param h Handler that receives the notification message.
1547     * @param what User-defined message code.
1548     * @param obj User object.
1549     */
1550    public void registerForSuppServiceFailed(Handler h, int what, Object obj){
1551        mSuppServiceFailedRegistrants.addUnique(h, what, obj);
1552    }
1553
1554    /**
1555     * Unregister for notifications when a supplementary service attempt fails.
1556     * Extraneous calls are tolerated silently
1557     *
1558     * @param h Handler to be removed from the registrant list.
1559     */
1560    public void unregisterForSuppServiceFailed(Handler h){
1561        mSuppServiceFailedRegistrants.remove(h);
1562    }
1563
1564    /**
1565     * Register for notifications when a sInCall VoicePrivacy is enabled
1566     *
1567     * @param h Handler that receives the notification message.
1568     * @param what User-defined message code.
1569     * @param obj User object.
1570     */
1571    public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
1572        mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
1573    }
1574
1575    /**
1576     * Unregister for notifications when a sInCall VoicePrivacy is enabled
1577     *
1578     * @param h Handler to be removed from the registrant list.
1579     */
1580    public void unregisterForInCallVoicePrivacyOn(Handler h){
1581        mInCallVoicePrivacyOnRegistrants.remove(h);
1582    }
1583
1584    /**
1585     * Register for notifications when a sInCall VoicePrivacy is disabled
1586     *
1587     * @param h Handler that receives the notification message.
1588     * @param what User-defined message code.
1589     * @param obj User object.
1590     */
1591    public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
1592        mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
1593    }
1594
1595    /**
1596     * Unregister for notifications when a sInCall VoicePrivacy is disabled
1597     *
1598     * @param h Handler to be removed from the registrant list.
1599     */
1600    public void unregisterForInCallVoicePrivacyOff(Handler h){
1601        mInCallVoicePrivacyOffRegistrants.remove(h);
1602    }
1603
1604    /**
1605     * Register for notifications when CDMA call waiting comes
1606     *
1607     * @param h Handler that receives the notification message.
1608     * @param what User-defined message code.
1609     * @param obj User object.
1610     */
1611    public void registerForCallWaiting(Handler h, int what, Object obj){
1612        mCallWaitingRegistrants.addUnique(h, what, obj);
1613    }
1614
1615    /**
1616     * Unregister for notifications when CDMA Call waiting comes
1617     * @param h Handler to be removed from the registrant list.
1618     */
1619    public void unregisterForCallWaiting(Handler h){
1620        mCallWaitingRegistrants.remove(h);
1621    }
1622
1623
1624    /**
1625     * Register for signal information notifications from the network.
1626     * Message.obj will contain an AsyncResult.
1627     * AsyncResult.result will be a SuppServiceNotification instance.
1628     *
1629     * @param h Handler that receives the notification message.
1630     * @param what User-defined message code.
1631     * @param obj User object.
1632     */
1633
1634    public void registerForSignalInfo(Handler h, int what, Object obj){
1635        mSignalInfoRegistrants.addUnique(h, what, obj);
1636    }
1637
1638    /**
1639     * Unregisters for signal information notifications.
1640     * Extraneous calls are tolerated silently
1641     *
1642     * @param h Handler to be removed from the registrant list.
1643     */
1644    public void unregisterForSignalInfo(Handler h){
1645        mSignalInfoRegistrants.remove(h);
1646    }
1647
1648    /**
1649     * Register for display information notifications from the network.
1650     * Message.obj will contain an AsyncResult.
1651     * AsyncResult.result will be a SuppServiceNotification instance.
1652     *
1653     * @param h Handler that receives the notification message.
1654     * @param what User-defined message code.
1655     * @param obj User object.
1656     */
1657    public void registerForDisplayInfo(Handler h, int what, Object obj){
1658        mDisplayInfoRegistrants.addUnique(h, what, obj);
1659    }
1660
1661    /**
1662     * Unregisters for display information notifications.
1663     * Extraneous calls are tolerated silently
1664     *
1665     * @param h Handler to be removed from the registrant list.
1666     */
1667    public void unregisterForDisplayInfo(Handler h) {
1668        mDisplayInfoRegistrants.remove(h);
1669    }
1670
1671    /**
1672     * Register for notifications when CDMA OTA Provision status change
1673     *
1674     * @param h Handler that receives the notification message.
1675     * @param what User-defined message code.
1676     * @param obj User object.
1677     */
1678    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){
1679        mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
1680    }
1681
1682    /**
1683     * Unregister for notifications when CDMA OTA Provision status change
1684     * @param h Handler to be removed from the registrant list.
1685     */
1686    public void unregisterForCdmaOtaStatusChange(Handler h){
1687        mCdmaOtaStatusChangeRegistrants.remove(h);
1688    }
1689
1690    /**
1691     * Registration point for subscription info ready
1692     * @param h handler to notify
1693     * @param what what code of message when delivered
1694     * @param obj placed in Message.obj
1695     */
1696    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){
1697        mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
1698    }
1699
1700    /**
1701     * Unregister for notifications for subscription info
1702     * @param h Handler to be removed from the registrant list.
1703     */
1704    public void unregisterForSubscriptionInfoReady(Handler h){
1705        mSubscriptionInfoReadyRegistrants.remove(h);
1706    }
1707
1708    /**
1709     * Sets an event to be fired when the telephony system processes
1710     * a post-dial character on an outgoing call.<p>
1711     *
1712     * Messages of type <code>what</code> will be sent to <code>h</code>.
1713     * The <code>obj</code> field of these Message's will be instances of
1714     * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
1715     * a Connection object.<p>
1716     *
1717     * Message.arg1 will be the post dial character being processed,
1718     * or 0 ('\0') if end of string.<p>
1719     *
1720     * If Connection.getPostDialState() == WAIT,
1721     * the application must call
1722     * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
1723     * Connection.proceedAfterWaitChar()} or
1724     * {@link com.android.internal.telephony.Connection#cancelPostDial()
1725     * Connection.cancelPostDial()}
1726     * for the telephony system to continue playing the post-dial
1727     * DTMF sequence.<p>
1728     *
1729     * If Connection.getPostDialState() == WILD,
1730     * the application must call
1731     * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
1732     * Connection.proceedAfterWildChar()}
1733     * or
1734     * {@link com.android.internal.telephony.Connection#cancelPostDial()
1735     * Connection.cancelPostDial()}
1736     * for the telephony system to continue playing the
1737     * post-dial DTMF sequence.<p>
1738     *
1739     */
1740    public void registerForPostDialCharacter(Handler h, int what, Object obj){
1741        mPostDialCharacterRegistrants.addUnique(h, what, obj);
1742    }
1743
1744    public void unregisterForPostDialCharacter(Handler h){
1745        mPostDialCharacterRegistrants.remove(h);
1746    }
1747
1748    /**
1749     * Register for TTY mode change notifications from the network.
1750     * Message.obj will contain an AsyncResult.
1751     * AsyncResult.result will be an Integer containing new mode.
1752     *
1753     * @param h Handler that receives the notification message.
1754     * @param what User-defined message code.
1755     * @param obj User object.
1756     */
1757    public void registerForTtyModeReceived(Handler h, int what, Object obj){
1758        mTtyModeReceivedRegistrants.addUnique(h, what, obj);
1759    }
1760
1761    /**
1762     * Unregisters for TTY mode change notifications.
1763     * Extraneous calls are tolerated silently
1764     *
1765     * @param h Handler to be removed from the registrant list.
1766     */
1767    public void unregisterForTtyModeReceived(Handler h) {
1768        mTtyModeReceivedRegistrants.remove(h);
1769    }
1770
1771    /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
1772     * 1. APIs to access list of calls
1773     * 2. APIs to check if any active call, which has connection other than
1774     * disconnected ones, pleaser refer to Call.isIdle()
1775     * 3. APIs to return first active call
1776     * 4. APIs to return the connections of first active call
1777     * 5. APIs to return other property of first active call
1778     */
1779
1780    /**
1781     * @return list of all ringing calls
1782     */
1783    public List<Call> getRingingCalls() {
1784        return Collections.unmodifiableList(mRingingCalls);
1785    }
1786
1787    /**
1788     * @return list of all foreground calls
1789     */
1790    public List<Call> getForegroundCalls() {
1791        return Collections.unmodifiableList(mForegroundCalls);
1792    }
1793
1794    /**
1795     * @return list of all background calls
1796     */
1797    public List<Call> getBackgroundCalls() {
1798        return Collections.unmodifiableList(mBackgroundCalls);
1799    }
1800
1801    /**
1802     * Return true if there is at least one active foreground call
1803     */
1804    public boolean hasActiveFgCall() {
1805        return (getFirstActiveCall(mForegroundCalls) != null);
1806    }
1807
1808    /**
1809     * Return true if there is at least one active foreground call
1810     * on a particular subId or an active sip call
1811     */
1812    public boolean hasActiveFgCall(int subId) {
1813        return (getFirstActiveCall(mForegroundCalls, subId) != null);
1814    }
1815
1816    /**
1817     * Return true if there is at least one active background call
1818     */
1819    public boolean hasActiveBgCall() {
1820        // TODO since hasActiveBgCall may get called often
1821        // better to cache it to improve performance
1822        return (getFirstActiveCall(mBackgroundCalls) != null);
1823    }
1824
1825    /**
1826     * Return true if there is at least one active background call
1827     * on a particular subId or an active sip call
1828     */
1829    public boolean hasActiveBgCall(int subId) {
1830        // TODO since hasActiveBgCall may get called often
1831        // better to cache it to improve performance
1832        return (getFirstActiveCall(mBackgroundCalls, subId) != null);
1833    }
1834
1835    /**
1836     * Return true if there is at least one active ringing call
1837     *
1838     */
1839    public boolean hasActiveRingingCall() {
1840        return (getFirstActiveCall(mRingingCalls) != null);
1841    }
1842
1843    /**
1844     * Return true if there is at least one active ringing call
1845     */
1846    public boolean hasActiveRingingCall(int subId) {
1847        return (getFirstActiveCall(mRingingCalls, subId) != null);
1848    }
1849
1850    /**
1851     * return the active foreground call from foreground calls
1852     *
1853     * Active call means the call is NOT in Call.State.IDLE
1854     *
1855     * 1. If there is active foreground call, return it
1856     * 2. If there is no active foreground call, return the
1857     *    foreground call associated with default phone, which state is IDLE.
1858     * 3. If there is no phone registered at all, return null.
1859     *
1860     */
1861    public Call getActiveFgCall() {
1862        Call call = getFirstNonIdleCall(mForegroundCalls);
1863        if (call == null) {
1864            call = (mDefaultPhone == null)
1865                    ? null
1866                    : mDefaultPhone.getForegroundCall();
1867        }
1868        return call;
1869    }
1870
1871    public Call getActiveFgCall(int subId) {
1872        Call call = getFirstNonIdleCall(mForegroundCalls, subId);
1873        if (call == null) {
1874            Phone phone = getPhone(subId);
1875            call = (phone == null)
1876                    ? null
1877                    : phone.getForegroundCall();
1878        }
1879        return call;
1880    }
1881
1882    // Returns the first call that is not in IDLE state. If both active calls
1883    // and disconnecting/disconnected calls exist, return the first active call.
1884    private Call getFirstNonIdleCall(List<Call> calls) {
1885        Call result = null;
1886        for (Call call : calls) {
1887            if (!call.isIdle()) {
1888                return call;
1889            } else if (call.getState() != Call.State.IDLE) {
1890                if (result == null) result = call;
1891            }
1892        }
1893        return result;
1894    }
1895
1896    // Returns the first call that is not in IDLE state. If both active calls
1897    // and disconnecting/disconnected calls exist, return the first active call.
1898    private Call getFirstNonIdleCall(List<Call> calls, int subId) {
1899        Call result = null;
1900        for (Call call : calls) {
1901            if ((call.getPhone().getSubId() == subId) ||
1902                    (call.getPhone() instanceof SipPhone)) {
1903                if (!call.isIdle()) {
1904                    return call;
1905                } else if (call.getState() != Call.State.IDLE) {
1906                    if (result == null) result = call;
1907                }
1908            }
1909        }
1910        return result;
1911    }
1912
1913    /**
1914     * return one active background call from background calls
1915     *
1916     * Active call means the call is NOT idle defined by Call.isIdle()
1917     *
1918     * 1. If there is only one active background call, return it
1919     * 2. If there is more than one active background call, return the first one
1920     * 3. If there is no active background call, return the background call
1921     *    associated with default phone, which state is IDLE.
1922     * 4. If there is no background call at all, return null.
1923     *
1924     * Complete background calls list can be get by getBackgroundCalls()
1925     */
1926    public Call getFirstActiveBgCall() {
1927        Call call = getFirstNonIdleCall(mBackgroundCalls);
1928        if (call == null) {
1929            call = (mDefaultPhone == null)
1930                    ? null
1931                    : mDefaultPhone.getBackgroundCall();
1932        }
1933        return call;
1934    }
1935
1936    /**
1937     * return one active background call from background calls of the
1938     * requested subId.
1939     *
1940     * Active call means the call is NOT idle defined by Call.isIdle()
1941     *
1942     * 1. If there is only one active background call on given sub or
1943     *    on SIP Phone, return it
1944     * 2. If there is more than one active background call, return the background call
1945     *    associated with the active sub.
1946     * 3. If there is no background call at all, return null.
1947     *
1948     * Complete background calls list can be get by getBackgroundCalls()
1949     */
1950    public Call getFirstActiveBgCall(int subId) {
1951        Phone phone = getPhone(subId);
1952        if (hasMoreThanOneHoldingCall(subId)) {
1953            return phone.getBackgroundCall();
1954        } else {
1955            Call call = getFirstNonIdleCall(mBackgroundCalls, subId);
1956            if (call == null) {
1957                call = (phone == null)
1958                        ? null
1959                        : phone.getBackgroundCall();
1960            }
1961            return call;
1962        }
1963    }
1964
1965    /**
1966     * return one active ringing call from ringing calls
1967     *
1968     * Active call means the call is NOT idle defined by Call.isIdle()
1969     *
1970     * 1. If there is only one active ringing call, return it
1971     * 2. If there is more than one active ringing call, return the first one
1972     * 3. If there is no active ringing call, return the ringing call
1973     *    associated with default phone, which state is IDLE.
1974     * 4. If there is no ringing call at all, return null.
1975     *
1976     * Complete ringing calls list can be get by getRingingCalls()
1977     */
1978    public Call getFirstActiveRingingCall() {
1979        Call call = getFirstNonIdleCall(mRingingCalls);
1980        if (call == null) {
1981            call = (mDefaultPhone == null)
1982                    ? null
1983                    : mDefaultPhone.getRingingCall();
1984        }
1985        return call;
1986    }
1987
1988    public Call getFirstActiveRingingCall(int subId) {
1989        Phone phone = getPhone(subId);
1990        Call call = getFirstNonIdleCall(mRingingCalls, subId);
1991        if (call == null) {
1992            call = (phone == null)
1993                    ? null
1994                    : phone.getRingingCall();
1995        }
1996        return call;
1997    }
1998
1999    /**
2000     * @return the state of active foreground call
2001     * return IDLE if there is no active foreground call
2002     */
2003    public Call.State getActiveFgCallState() {
2004        Call fgCall = getActiveFgCall();
2005
2006        if (fgCall != null) {
2007            return fgCall.getState();
2008        }
2009
2010        return Call.State.IDLE;
2011    }
2012
2013    public Call.State getActiveFgCallState(int subId) {
2014        Call fgCall = getActiveFgCall(subId);
2015
2016        if (fgCall != null) {
2017            return fgCall.getState();
2018        }
2019
2020        return Call.State.IDLE;
2021    }
2022
2023    /**
2024     * @return the connections of active foreground call
2025     * return empty list if there is no active foreground call
2026     */
2027    public List<Connection> getFgCallConnections() {
2028        Call fgCall = getActiveFgCall();
2029        if ( fgCall != null) {
2030            return fgCall.getConnections();
2031        }
2032        return mEmptyConnections;
2033    }
2034
2035    /**
2036     * @return the connections of active foreground call
2037     * return empty list if there is no active foreground call
2038     */
2039    public List<Connection> getFgCallConnections(int subId) {
2040        Call fgCall = getActiveFgCall(subId);
2041        if ( fgCall != null) {
2042            return fgCall.getConnections();
2043        }
2044        return mEmptyConnections;
2045    }
2046
2047    /**
2048     * @return the connections of active background call
2049     * return empty list if there is no active background call
2050     */
2051    public List<Connection> getBgCallConnections() {
2052        Call bgCall = getFirstActiveBgCall();
2053        if ( bgCall != null) {
2054            return bgCall.getConnections();
2055        }
2056        return mEmptyConnections;
2057    }
2058
2059    /**
2060     * @return the connections of active background call
2061     * return empty list if there is no active background call
2062     */
2063    public List<Connection> getBgCallConnections(int subId) {
2064        Call bgCall = getFirstActiveBgCall(subId);
2065        if ( bgCall != null) {
2066            return bgCall.getConnections();
2067        }
2068        return mEmptyConnections;
2069    }
2070
2071    /**
2072     * @return the latest connection of active foreground call
2073     * return null if there is no active foreground call
2074     */
2075    public Connection getFgCallLatestConnection() {
2076        Call fgCall = getActiveFgCall();
2077        if ( fgCall != null) {
2078            return fgCall.getLatestConnection();
2079        }
2080        return null;
2081    }
2082
2083    /**
2084     * @return the latest connection of active foreground call
2085     * return null if there is no active foreground call
2086     */
2087    public Connection getFgCallLatestConnection(int subId) {
2088        Call fgCall = getActiveFgCall(subId);
2089        if ( fgCall != null) {
2090            return fgCall.getLatestConnection();
2091        }
2092        return null;
2093    }
2094
2095    /**
2096     * @return true if there is at least one Foreground call in disconnected state
2097     */
2098    public boolean hasDisconnectedFgCall() {
2099        return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
2100    }
2101
2102    /**
2103     * @return true if there is at least one Foreground call in disconnected state
2104     */
2105    public boolean hasDisconnectedFgCall(int subId) {
2106        return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED,
2107                subId) != null);
2108    }
2109
2110    /**
2111     * @return true if there is at least one background call in disconnected state
2112     */
2113    public boolean hasDisconnectedBgCall() {
2114        return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
2115    }
2116
2117    /**
2118     * @return true if there is at least one background call in disconnected state
2119     */
2120    public boolean hasDisconnectedBgCall(int subId) {
2121        return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED,
2122                subId) != null);
2123    }
2124
2125
2126    /**
2127     * @return the first active call from a call list
2128     */
2129    private  Call getFirstActiveCall(ArrayList<Call> calls) {
2130        for (Call call : calls) {
2131            if (!call.isIdle()) {
2132                return call;
2133            }
2134        }
2135        return null;
2136    }
2137
2138    /**
2139     * @return the first active call from a call list
2140     */
2141    private  Call getFirstActiveCall(ArrayList<Call> calls, int subId) {
2142        for (Call call : calls) {
2143            if ((!call.isIdle()) && ((call.getPhone().getSubId() == subId) ||
2144                    (call.getPhone() instanceof SipPhone))) {
2145                return call;
2146            }
2147        }
2148        return null;
2149    }
2150
2151    /**
2152     * @return the first call in a the Call.state from a call list
2153     */
2154    private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
2155        for (Call call : calls) {
2156            if (call.getState() == state) {
2157                return call;
2158            }
2159        }
2160        return null;
2161    }
2162
2163    /**
2164     * @return the first call in a the Call.state from a call list
2165     */
2166    private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state,
2167            int subId) {
2168        for (Call call : calls) {
2169            if ((call.getState() == state) ||
2170                ((call.getPhone().getSubId() == subId) ||
2171                (call.getPhone() instanceof SipPhone))) {
2172                return call;
2173            }
2174        }
2175        return null;
2176    }
2177
2178    private boolean hasMoreThanOneRingingCall() {
2179        int count = 0;
2180        for (Call call : mRingingCalls) {
2181            if (call.getState().isRinging()) {
2182                if (++count > 1) return true;
2183            }
2184        }
2185        return false;
2186    }
2187
2188    /**
2189     * @return true if more than one active ringing call exists on
2190     * the active subId.
2191     * This checks for the active calls on provided
2192     * subId and also active calls on SIP Phone.
2193     *
2194     */
2195    private boolean hasMoreThanOneRingingCall(int subId) {
2196        int count = 0;
2197        for (Call call : mRingingCalls) {
2198            if ((call.getState().isRinging()) &&
2199                ((call.getPhone().getSubId() == subId) ||
2200                (call.getPhone() instanceof SipPhone))) {
2201                if (++count > 1) return true;
2202            }
2203        }
2204        return false;
2205    }
2206
2207    /**
2208     * @return true if more than one active background call exists on
2209     * the provided subId.
2210     * This checks for the background calls on provided
2211     * subId and also background calls on SIP Phone.
2212     *
2213     */
2214    private boolean hasMoreThanOneHoldingCall(int subId) {
2215        int count = 0;
2216        for (Call call : mBackgroundCalls) {
2217            if ((call.getState() == Call.State.HOLDING) &&
2218                ((call.getPhone().getSubId() == subId) ||
2219                (call.getPhone() instanceof SipPhone))) {
2220                if (++count > 1) return true;
2221            }
2222        }
2223        return false;
2224    }
2225
2226    /* FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
2227    private boolean isServiceStateInService() {
2228        boolean bInService = false;
2229
2230        for (Phone phone : mPhones) {
2231            bInService = (phone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
2232            if (bInService) {
2233                break;
2234            }
2235        }
2236
2237        if (VDBG) Rlog.d(LOG_TAG, "[isServiceStateInService] bInService = " + bInService);
2238        return bInService;
2239    }
2240    */
2241
2242    private class CallManagerHandler extends Handler {
2243        @Override
2244        public void handleMessage(Message msg) {
2245
2246            switch (msg.what) {
2247                case EVENT_DISCONNECT:
2248                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_DISCONNECT)");
2249                    mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2250                    // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
2251                    //mIsEccDialing = false;
2252                    break;
2253                case EVENT_PRECISE_CALL_STATE_CHANGED:
2254                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)");
2255                    mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2256                    break;
2257                case EVENT_NEW_RINGING_CONNECTION:
2258                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
2259                    Connection c = (Connection) ((AsyncResult) msg.obj).result;
2260                    int subId = c.getCall().getPhone().getSubId();
2261                    if (getActiveFgCallState(subId).isDialing() || hasMoreThanOneRingingCall()) {
2262                        try {
2263                            Rlog.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
2264                            c.getCall().hangup();
2265                        } catch (CallStateException e) {
2266                            Rlog.w(LOG_TAG, "new ringing connection", e);
2267                        }
2268                    } else {
2269                        mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2270                    }
2271                    break;
2272                case EVENT_UNKNOWN_CONNECTION:
2273                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_UNKNOWN_CONNECTION)");
2274                    mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2275                    break;
2276                case EVENT_INCOMING_RING:
2277                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)");
2278                    // The event may come from RIL who's not aware of an ongoing fg call
2279                    if (!hasActiveFgCall()) {
2280                        mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2281                    }
2282                    break;
2283                case EVENT_RINGBACK_TONE:
2284                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RINGBACK_TONE)");
2285                    mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2286                    break;
2287                case EVENT_IN_CALL_VOICE_PRIVACY_ON:
2288                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_ON)");
2289                    mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2290                    break;
2291                case EVENT_IN_CALL_VOICE_PRIVACY_OFF:
2292                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_OFF)");
2293                    mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2294                    break;
2295                case EVENT_CALL_WAITING:
2296                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_CALL_WAITING)");
2297                    mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2298                    break;
2299                case EVENT_DISPLAY_INFO:
2300                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_DISPLAY_INFO)");
2301                    mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2302                    break;
2303                case EVENT_SIGNAL_INFO:
2304                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SIGNAL_INFO)");
2305                    mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2306                    break;
2307                case EVENT_CDMA_OTA_STATUS_CHANGE:
2308                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_CDMA_OTA_STATUS_CHANGE)");
2309                    mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2310                    break;
2311                case EVENT_RESEND_INCALL_MUTE:
2312                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RESEND_INCALL_MUTE)");
2313                    mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2314                    break;
2315                case EVENT_MMI_INITIATE:
2316                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_INITIATE)");
2317                    mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2318                    break;
2319                case EVENT_MMI_COMPLETE:
2320                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
2321                    mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2322                    break;
2323                case EVENT_ECM_TIMER_RESET:
2324                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_ECM_TIMER_RESET)");
2325                    mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2326                    break;
2327                case EVENT_SUBSCRIPTION_INFO_READY:
2328                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SUBSCRIPTION_INFO_READY)");
2329                    mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2330                    break;
2331                case EVENT_SUPP_SERVICE_FAILED:
2332                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SUPP_SERVICE_FAILED)");
2333                    mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2334                    break;
2335                case EVENT_SERVICE_STATE_CHANGED:
2336                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SERVICE_STATE_CHANGED)");
2337                    mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2338                    // FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
2339                    //setAudioMode();
2340                    break;
2341                case EVENT_POST_DIAL_CHARACTER:
2342                    // we need send the character that is being processed in msg.arg1
2343                    // so can't use notifyRegistrants()
2344                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_POST_DIAL_CHARACTER)");
2345                    for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
2346                        Message notifyMsg;
2347                        notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
2348                        notifyMsg.obj = msg.obj;
2349                        notifyMsg.arg1 = msg.arg1;
2350                        notifyMsg.sendToTarget();
2351                    }
2352                    break;
2353                case EVENT_ONHOLD_TONE:
2354                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_ONHOLD_TONE)");
2355                    mOnHoldToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2356                    break;
2357                case EVENT_TTY_MODE_RECEIVED:
2358                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_TTY_MODE_RECEIVED)");
2359                    mTtyModeReceivedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
2360                    break;
2361                /* FIXME Taken from klp-sprout-dev but setAudioMode was removed in L.
2362                case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
2363                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RADIO_OFF_OR_NOT_AVAILABLE)");
2364                    setAudioMode();
2365                    break;
2366                */
2367            }
2368        }
2369    };
2370
2371    @Override
2372    public String toString() {
2373        Call call;
2374        StringBuilder b = new StringBuilder();
2375        for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
2376            b.append("CallManager {");
2377            b.append("\nstate = " + getState(i));
2378            call = getActiveFgCall(i);
2379            if (call != null) {
2380                b.append("\n- Foreground: " + getActiveFgCallState(i));
2381                b.append(" from " + call.getPhone());
2382                b.append("\n  Conn: ").append(getFgCallConnections(i));
2383            }
2384            call = getFirstActiveBgCall(i);
2385            if (call != null) {
2386                b.append("\n- Background: " + call.getState());
2387                b.append(" from " + call.getPhone());
2388                b.append("\n  Conn: ").append(getBgCallConnections(i));
2389            }
2390            call = getFirstActiveRingingCall(i);
2391            if (call != null) {
2392                b.append("\n- Ringing: " +call.getState());
2393                b.append(" from " + call.getPhone());
2394            }
2395        }
2396
2397        for (Phone phone : getAllPhones()) {
2398            if (phone != null) {
2399                b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
2400                        + ", state = " + phone.getState());
2401                call = phone.getForegroundCall();
2402                if (call != null) {
2403                    b.append("\n- Foreground: ").append(call);
2404                }
2405                call = phone.getBackgroundCall();
2406                if (call != null) {
2407                    b.append(" Background: ").append(call);
2408                }
2409                call = phone.getRingingCall();
2410                if (call != null) {
2411                    b.append(" Ringing: ").append(call);
2412                }
2413            }
2414        }
2415        b.append("\n}");
2416        return b.toString();
2417    }
2418}
2419