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