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