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