1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.telephony;
18
19import com.android.internal.telephony.sip.SipPhone;
20
21import android.content.Context;
22import android.media.AudioManager;
23import android.os.AsyncResult;
24import android.os.Handler;
25import android.os.Message;
26import android.os.RegistrantList;
27import android.os.Registrant;
28import android.telephony.PhoneStateListener;
29import android.telephony.ServiceState;
30import android.telephony.Rlog;
31
32import java.util.ArrayList;
33import java.util.Collections;
34import java.util.List;
35
36
37
38/**
39 * @hide
40 *
41 * CallManager class provides an abstract layer for PhoneApp to access
42 * and control calls. It implements Phone interface.
43 *
44 * CallManager provides call and connection control as well as
45 * channel capability.
46 *
47 * There are three categories of APIs CallManager provided
48 *
49 *  1. Call control and operation, such as dial() and hangup()
50 *  2. Channel capabilities, such as CanConference()
51 *  3. Register notification
52 *
53 *
54 */
55public final class CallManager {
56
57    private static final String LOG_TAG ="CallManager";
58    private static final boolean DBG = true;
59    private static final boolean VDBG = false;
60
61    private static final int EVENT_DISCONNECT = 100;
62    private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101;
63    private static final int EVENT_NEW_RINGING_CONNECTION = 102;
64    private static final int EVENT_UNKNOWN_CONNECTION = 103;
65    private static final int EVENT_INCOMING_RING = 104;
66    private static final int EVENT_RINGBACK_TONE = 105;
67    private static final int EVENT_IN_CALL_VOICE_PRIVACY_ON = 106;
68    private static final int EVENT_IN_CALL_VOICE_PRIVACY_OFF = 107;
69    private static final int EVENT_CALL_WAITING = 108;
70    private static final int EVENT_DISPLAY_INFO = 109;
71    private static final int EVENT_SIGNAL_INFO = 110;
72    private static final int EVENT_CDMA_OTA_STATUS_CHANGE = 111;
73    private static final int EVENT_RESEND_INCALL_MUTE = 112;
74    private static final int EVENT_MMI_INITIATE = 113;
75    private static final int EVENT_MMI_COMPLETE = 114;
76    private static final int EVENT_ECM_TIMER_RESET = 115;
77    private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
78    private static final int EVENT_SUPP_SERVICE_FAILED = 117;
79    private static final int EVENT_SERVICE_STATE_CHANGED = 118;
80    private static final int EVENT_POST_DIAL_CHARACTER = 119;
81
82    // Singleton instance
83    private static final CallManager INSTANCE = new CallManager();
84
85    // list of registered phones, which are PhoneBase objs
86    private final ArrayList<Phone> mPhones;
87
88    // list of supported ringing calls
89    private final ArrayList<Call> mRingingCalls;
90
91    // list of supported background calls
92    private final ArrayList<Call> mBackgroundCalls;
93
94    // list of supported foreground calls
95    private final ArrayList<Call> mForegroundCalls;
96
97    // empty connection list
98    private final ArrayList<Connection> mEmptyConnections = new ArrayList<Connection>();
99
100    // default phone as the first phone registered, which is PhoneBase obj
101    private Phone mDefaultPhone;
102
103    private boolean mSpeedUpAudioForMtCall = false;
104
105    // state registrants
106    protected final RegistrantList mPreciseCallStateRegistrants
107    = new RegistrantList();
108
109    protected final RegistrantList mNewRingingConnectionRegistrants
110    = new RegistrantList();
111
112    protected final RegistrantList mIncomingRingRegistrants
113    = new RegistrantList();
114
115    protected final RegistrantList mDisconnectRegistrants
116    = new RegistrantList();
117
118    protected final RegistrantList mMmiRegistrants
119    = new RegistrantList();
120
121    protected final RegistrantList mUnknownConnectionRegistrants
122    = new RegistrantList();
123
124    protected final RegistrantList mRingbackToneRegistrants
125    = new RegistrantList();
126
127    protected final RegistrantList mInCallVoicePrivacyOnRegistrants
128    = new RegistrantList();
129
130    protected final RegistrantList mInCallVoicePrivacyOffRegistrants
131    = new RegistrantList();
132
133    protected final RegistrantList mCallWaitingRegistrants
134    = new RegistrantList();
135
136    protected final RegistrantList mDisplayInfoRegistrants
137    = new RegistrantList();
138
139    protected final RegistrantList mSignalInfoRegistrants
140    = new RegistrantList();
141
142    protected final RegistrantList mCdmaOtaStatusChangeRegistrants
143    = new RegistrantList();
144
145    protected final RegistrantList mResendIncallMuteRegistrants
146    = new RegistrantList();
147
148    protected final RegistrantList mMmiInitiateRegistrants
149    = new RegistrantList();
150
151    protected final RegistrantList mMmiCompleteRegistrants
152    = new RegistrantList();
153
154    protected final RegistrantList mEcmTimerResetRegistrants
155    = new RegistrantList();
156
157    protected final RegistrantList mSubscriptionInfoReadyRegistrants
158    = new RegistrantList();
159
160    protected final RegistrantList mSuppServiceFailedRegistrants
161    = new RegistrantList();
162
163    protected final RegistrantList mServiceStateChangedRegistrants
164    = new RegistrantList();
165
166    protected final RegistrantList mPostDialCharacterRegistrants
167    = new RegistrantList();
168
169    private CallManager() {
170        mPhones = new ArrayList<Phone>();
171        mRingingCalls = new ArrayList<Call>();
172        mBackgroundCalls = new ArrayList<Call>();
173        mForegroundCalls = new ArrayList<Call>();
174        mDefaultPhone = null;
175    }
176
177    /**
178     * get singleton instance of CallManager
179     * @return CallManager
180     */
181    public static CallManager getInstance() {
182        return INSTANCE;
183    }
184
185    /**
186     * Get the corresponding PhoneBase obj
187     *
188     * @param phone a Phone object
189     * @return the corresponding PhoneBase obj in Phone if Phone
190     * is a PhoneProxy obj
191     * or the Phone itself if Phone is not a PhoneProxy obj
192     */
193    private static Phone getPhoneBase(Phone phone) {
194        if (phone instanceof PhoneProxy) {
195            return phone.getForegroundCall().getPhone();
196        }
197        return phone;
198    }
199
200    /**
201     * Check if two phones refer to the same PhoneBase obj
202     *
203     * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager
204     *
205     * Both PhoneBase and PhoneProxy implement Phone interface, so
206     * they have same phone APIs, such as dial(). The real implementation, for
207     * example in GSM,  is in GSMPhone as extend from PhoneBase, so that
208     * foregroundCall.getPhone() returns GSMPhone obj. On the other hand,
209     * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class
210     * member of GSMPhone.
211     *
212     * So for phone returned by PhoneFacotry, which is used by PhoneApp,
213     *        phone.getForegroundCall().getPhone() != phone
214     * but
215     *        isSamePhone(phone, phone.getForegroundCall().getPhone()) == true
216     *
217     * @param p1 is the first Phone obj
218     * @param p2 is the second Phone obj
219     * @return true if p1 and p2 refer to the same phone
220     */
221    public static boolean isSamePhone(Phone p1, Phone p2) {
222        return (getPhoneBase(p1) == getPhoneBase(p2));
223    }
224
225    /**
226     * Returns all the registered phone objects.
227     * @return all the registered phone objects.
228     */
229    public List<Phone> getAllPhones() {
230        return Collections.unmodifiableList(mPhones);
231    }
232
233    /**
234     * Get current coarse-grained voice call state.
235     * If the Call Manager has an active call and call waiting occurs,
236     * then the phone state is RINGING not OFFHOOK
237     *
238     */
239    public PhoneConstants.State getState() {
240        PhoneConstants.State s = PhoneConstants.State.IDLE;
241
242        for (Phone phone : mPhones) {
243            if (phone.getState() == PhoneConstants.State.RINGING) {
244                s = PhoneConstants.State.RINGING;
245            } else if (phone.getState() == PhoneConstants.State.OFFHOOK) {
246                if (s == PhoneConstants.State.IDLE) s = PhoneConstants.State.OFFHOOK;
247            }
248        }
249        return s;
250    }
251
252    /**
253     * @return the service state of CallManager, which represents the
254     * highest priority state of all the service states of phones
255     *
256     * The priority is defined as
257     *
258     * STATE_IN_SERIVCE > STATE_OUT_OF_SERIVCE > STATE_EMERGENCY > STATE_POWER_OFF
259     *
260     */
261
262    public int getServiceState() {
263        int resultState = ServiceState.STATE_OUT_OF_SERVICE;
264
265        for (Phone phone : mPhones) {
266            int serviceState = phone.getServiceState().getState();
267            if (serviceState == ServiceState.STATE_IN_SERVICE) {
268                // IN_SERVICE has the highest priority
269                resultState = serviceState;
270                break;
271            } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
272                // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
273                // Note: EMERGENCY_ONLY is not in use at this moment
274                if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
275                        resultState == ServiceState.STATE_POWER_OFF) {
276                    resultState = serviceState;
277                }
278            } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
279                if (resultState == ServiceState.STATE_POWER_OFF) {
280                    resultState = serviceState;
281                }
282            }
283        }
284        return resultState;
285    }
286
287    /**
288     * Register phone to CallManager
289     * @param phone to be registered
290     * @return true if register successfully
291     */
292    public boolean registerPhone(Phone phone) {
293        Phone basePhone = getPhoneBase(phone);
294
295        if (basePhone != null && !mPhones.contains(basePhone)) {
296
297            if (DBG) {
298                Rlog.d(LOG_TAG, "registerPhone(" +
299                        phone.getPhoneName() + " " + phone + ")");
300            }
301
302            if (mPhones.isEmpty()) {
303                mDefaultPhone = basePhone;
304            }
305            mPhones.add(basePhone);
306            mRingingCalls.add(basePhone.getRingingCall());
307            mBackgroundCalls.add(basePhone.getBackgroundCall());
308            mForegroundCalls.add(basePhone.getForegroundCall());
309            registerForPhoneStates(basePhone);
310            return true;
311        }
312        return false;
313    }
314
315    /**
316     * unregister phone from CallManager
317     * @param phone to be unregistered
318     */
319    public void unregisterPhone(Phone phone) {
320        Phone basePhone = getPhoneBase(phone);
321
322        if (basePhone != null && mPhones.contains(basePhone)) {
323
324            if (DBG) {
325                Rlog.d(LOG_TAG, "unregisterPhone(" +
326                        phone.getPhoneName() + " " + phone + ")");
327            }
328
329            mPhones.remove(basePhone);
330            mRingingCalls.remove(basePhone.getRingingCall());
331            mBackgroundCalls.remove(basePhone.getBackgroundCall());
332            mForegroundCalls.remove(basePhone.getForegroundCall());
333            unregisterForPhoneStates(basePhone);
334            if (basePhone == mDefaultPhone) {
335                if (mPhones.isEmpty()) {
336                    mDefaultPhone = null;
337                } else {
338                    mDefaultPhone = mPhones.get(0);
339                }
340            }
341        }
342    }
343
344    /**
345     * return the default phone or null if no phone available
346     */
347    public Phone getDefaultPhone() {
348        return mDefaultPhone;
349    }
350
351    /**
352     * @return the phone associated with the foreground call
353     */
354    public Phone getFgPhone() {
355        return getActiveFgCall().getPhone();
356    }
357
358    /**
359     * @return the phone associated with the background call
360     */
361    public Phone getBgPhone() {
362        return getFirstActiveBgCall().getPhone();
363    }
364
365    /**
366     * @return the phone associated with the ringing call
367     */
368    public Phone getRingingPhone() {
369        return getFirstActiveRingingCall().getPhone();
370    }
371
372    public void setAudioMode() {
373        Context context = getContext();
374        if (context == null) return;
375        AudioManager audioManager = (AudioManager)
376                context.getSystemService(Context.AUDIO_SERVICE);
377
378        // change the audio mode and request/abandon audio focus according to phone state,
379        // but only on audio mode transitions
380        switch (getState()) {
381            case RINGING:
382                int curAudioMode = audioManager.getMode();
383                if (curAudioMode != AudioManager.MODE_RINGTONE) {
384                    // only request audio focus if the ringtone is going to be heard
385                    if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
386                        if (VDBG) Rlog.d(LOG_TAG, "requestAudioFocus on STREAM_RING");
387                        audioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
388                                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
389                    }
390                    if(!mSpeedUpAudioForMtCall) {
391                        audioManager.setMode(AudioManager.MODE_RINGTONE);
392                    }
393                }
394
395                if (mSpeedUpAudioForMtCall && (curAudioMode != AudioManager.MODE_IN_CALL)) {
396                    audioManager.setMode(AudioManager.MODE_IN_CALL);
397                }
398                break;
399            case OFFHOOK:
400                Phone offhookPhone = getFgPhone();
401                if (getActiveFgCallState() == Call.State.IDLE) {
402                    // There is no active Fg calls, the OFFHOOK state
403                    // is set by the Bg call. So set the phone to bgPhone.
404                    offhookPhone = getBgPhone();
405                }
406
407                int newAudioMode = AudioManager.MODE_IN_CALL;
408                if (offhookPhone instanceof SipPhone) {
409                    // enable IN_COMMUNICATION audio mode instead for sipPhone
410                    newAudioMode = AudioManager.MODE_IN_COMMUNICATION;
411                }
412                if (audioManager.getMode() != newAudioMode || mSpeedUpAudioForMtCall) {
413                    // request audio focus before setting the new mode
414                    if (VDBG) Rlog.d(LOG_TAG, "requestAudioFocus on STREAM_VOICE_CALL");
415                    audioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
416                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
417                    audioManager.setMode(newAudioMode);
418                }
419                mSpeedUpAudioForMtCall = false;
420                break;
421            case IDLE:
422                if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
423                    audioManager.setMode(AudioManager.MODE_NORMAL);
424                    if (VDBG) Rlog.d(LOG_TAG, "abandonAudioFocus");
425                    // abandon audio focus after the mode has been set back to normal
426                    audioManager.abandonAudioFocusForCall();
427                }
428                mSpeedUpAudioForMtCall = false;
429                break;
430        }
431    }
432
433    private Context getContext() {
434        Phone defaultPhone = getDefaultPhone();
435        return ((defaultPhone == null) ? null : defaultPhone.getContext());
436    }
437
438    private void registerForPhoneStates(Phone phone) {
439        // for common events supported by all phones
440        phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
441        phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
442        phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
443        phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
444        phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
445        phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
446        phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
447        phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
448        phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
449        phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
450        phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
451        phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
452        phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
453        phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
454        phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
455
456        // for events supported only by GSM and CDMA phone
457        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
458                phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
459            phone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL_CHARACTER, null);
460        }
461
462        // for events supported only by CDMA phone
463        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
464            phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
465            phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
466            phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
467            phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
468        }
469    }
470
471    private void unregisterForPhoneStates(Phone phone) {
472        //  for common events supported by all phones
473        phone.unregisterForPreciseCallStateChanged(mHandler);
474        phone.unregisterForDisconnect(mHandler);
475        phone.unregisterForNewRingingConnection(mHandler);
476        phone.unregisterForUnknownConnection(mHandler);
477        phone.unregisterForIncomingRing(mHandler);
478        phone.unregisterForRingbackTone(mHandler);
479        phone.unregisterForInCallVoicePrivacyOn(mHandler);
480        phone.unregisterForInCallVoicePrivacyOff(mHandler);
481        phone.unregisterForDisplayInfo(mHandler);
482        phone.unregisterForSignalInfo(mHandler);
483        phone.unregisterForResendIncallMute(mHandler);
484        phone.unregisterForMmiInitiate(mHandler);
485        phone.unregisterForMmiComplete(mHandler);
486        phone.unregisterForSuppServiceFailed(mHandler);
487        phone.unregisterForServiceStateChanged(mHandler);
488
489        // for events supported only by GSM and CDMA phone
490        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM ||
491                phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) {
492            phone.setOnPostDialCharacter(null, EVENT_POST_DIAL_CHARACTER, null);
493        }
494
495        // for events supported only by CDMA phone
496        if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA ){
497            phone.unregisterForCdmaOtaStatusChange(mHandler);
498            phone.unregisterForSubscriptionInfoReady(mHandler);
499            phone.unregisterForCallWaiting(mHandler);
500            phone.unregisterForEcmTimerReset(mHandler);
501        }
502    }
503
504    /**
505     * Answers a ringing or waiting call.
506     *
507     * Active call, if any, go on hold.
508     * If active call can't be held, i.e., a background call of the same channel exists,
509     * the active call will be hang up.
510     *
511     * Answering occurs asynchronously, and final notification occurs via
512     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
513     * java.lang.Object) registerForPreciseCallStateChanged()}.
514     *
515     * @exception CallStateException when call is not ringing or waiting
516     */
517    public void acceptCall(Call ringingCall) throws CallStateException {
518        Phone ringingPhone = ringingCall.getPhone();
519
520        if (VDBG) {
521            Rlog.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")");
522            Rlog.d(LOG_TAG, toString());
523        }
524
525        if ( hasActiveFgCall() ) {
526            Phone activePhone = getActiveFgCall().getPhone();
527            boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
528            boolean sameChannel = (activePhone == ringingPhone);
529
530            if (VDBG) {
531                Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
532            }
533
534            if (sameChannel && hasBgCall) {
535                getActiveFgCall().hangup();
536            } else if (!sameChannel && !hasBgCall) {
537                activePhone.switchHoldingAndActive();
538            } else if (!sameChannel && hasBgCall) {
539                getActiveFgCall().hangup();
540            }
541        }
542
543        Context context = getContext();
544        if (context == null) {
545            Rlog.d(LOG_TAG, "Speedup Audio Path enhancement: Context is null");
546        } else if (context.getResources().getBoolean(
547                com.android.internal.R.bool.config_speed_up_audio_on_mt_calls)) {
548            Rlog.d(LOG_TAG, "Speedup Audio Path enhancement");
549            AudioManager audioManager = (AudioManager)
550                    context.getSystemService(Context.AUDIO_SERVICE);
551            int currMode = audioManager.getMode();
552            if ((currMode != AudioManager.MODE_IN_CALL) && !(ringingPhone instanceof SipPhone)) {
553                Rlog.d(LOG_TAG, "setAudioMode Setting audio mode from " +
554                                currMode + " to " + AudioManager.MODE_IN_CALL);
555                audioManager.setMode(AudioManager.MODE_IN_CALL);
556                mSpeedUpAudioForMtCall = true;
557            }
558        }
559
560        ringingPhone.acceptCall();
561
562        if (VDBG) {
563            Rlog.d(LOG_TAG, "End acceptCall(" +ringingCall + ")");
564            Rlog.d(LOG_TAG, toString());
565        }
566    }
567
568    /**
569     * Reject (ignore) a ringing call. In GSM, this means UDUB
570     * (User Determined User Busy). Reject occurs asynchronously,
571     * and final notification occurs via
572     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
573     * java.lang.Object) registerForPreciseCallStateChanged()}.
574     *
575     * @exception CallStateException when no call is ringing or waiting
576     */
577    public void rejectCall(Call ringingCall) throws CallStateException {
578        if (VDBG) {
579            Rlog.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
580            Rlog.d(LOG_TAG, toString());
581        }
582
583        Phone ringingPhone = ringingCall.getPhone();
584
585        ringingPhone.rejectCall();
586
587        if (VDBG) {
588            Rlog.d(LOG_TAG, "End rejectCall(" +ringingCall + ")");
589            Rlog.d(LOG_TAG, toString());
590        }
591    }
592
593    /**
594     * Places active call on hold, and makes held call active.
595     * Switch occurs asynchronously and may fail.
596     *
597     * There are 4 scenarios
598     * 1. only active call but no held call, aka, hold
599     * 2. no active call but only held call, aka, unhold
600     * 3. both active and held calls from same phone, aka, swap
601     * 4. active and held calls from different phones, aka, phone swap
602     *
603     * Final notification occurs via
604     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
605     * java.lang.Object) registerForPreciseCallStateChanged()}.
606     *
607     * @exception CallStateException if active call is ringing, waiting, or
608     * dialing/alerting, or heldCall can't be active.
609     * In these cases, this operation may not be performed.
610     */
611    public void switchHoldingAndActive(Call heldCall) throws CallStateException {
612        Phone activePhone = null;
613        Phone heldPhone = null;
614
615        if (VDBG) {
616            Rlog.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")");
617            Rlog.d(LOG_TAG, toString());
618        }
619
620        if (hasActiveFgCall()) {
621            activePhone = getActiveFgCall().getPhone();
622        }
623
624        if (heldCall != null) {
625            heldPhone = heldCall.getPhone();
626        }
627
628        if (activePhone != null) {
629            activePhone.switchHoldingAndActive();
630        }
631
632        if (heldPhone != null && heldPhone != activePhone) {
633            heldPhone.switchHoldingAndActive();
634        }
635
636        if (VDBG) {
637            Rlog.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")");
638            Rlog.d(LOG_TAG, toString());
639        }
640    }
641
642    /**
643     * Hangup foreground call and resume the specific background call
644     *
645     * Note: this is noop if there is no foreground call or the heldCall is null
646     *
647     * @param heldCall to become foreground
648     * @throws CallStateException
649     */
650    public void hangupForegroundResumeBackground(Call heldCall) throws CallStateException {
651        Phone foregroundPhone = null;
652        Phone backgroundPhone = null;
653
654        if (VDBG) {
655            Rlog.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")");
656            Rlog.d(LOG_TAG, toString());
657        }
658
659        if (hasActiveFgCall()) {
660            foregroundPhone = getFgPhone();
661            if (heldCall != null) {
662                backgroundPhone = heldCall.getPhone();
663                if (foregroundPhone == backgroundPhone) {
664                    getActiveFgCall().hangup();
665                } else {
666                // the call to be hangup and resumed belongs to different phones
667                    getActiveFgCall().hangup();
668                    switchHoldingAndActive(heldCall);
669                }
670            }
671        }
672
673        if (VDBG) {
674            Rlog.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")");
675            Rlog.d(LOG_TAG, toString());
676        }
677    }
678
679    /**
680     * Whether or not the phone can conference in the current phone
681     * state--that is, one call holding and one call active.
682     * @return true if the phone can conference; false otherwise.
683     */
684    public boolean canConference(Call heldCall) {
685        Phone activePhone = null;
686        Phone heldPhone = null;
687
688        if (hasActiveFgCall()) {
689            activePhone = getActiveFgCall().getPhone();
690        }
691
692        if (heldCall != null) {
693            heldPhone = heldCall.getPhone();
694        }
695
696        return heldPhone.getClass().equals(activePhone.getClass());
697    }
698
699    /**
700     * Conferences holding and active. Conference occurs asynchronously
701     * and may fail. Final notification occurs via
702     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
703     * java.lang.Object) registerForPreciseCallStateChanged()}.
704     *
705     * @exception CallStateException if canConference() would return false.
706     * In these cases, this operation may not be performed.
707     */
708    public void conference(Call heldCall) throws CallStateException {
709
710        if (VDBG) {
711            Rlog.d(LOG_TAG, "conference(" +heldCall + ")");
712            Rlog.d(LOG_TAG, toString());
713        }
714
715
716        Phone fgPhone = getFgPhone();
717        if (fgPhone instanceof SipPhone) {
718            ((SipPhone) fgPhone).conference(heldCall);
719        } else if (canConference(heldCall)) {
720            fgPhone.conference();
721        } else {
722            throw(new CallStateException("Can't conference foreground and selected background call"));
723        }
724
725        if (VDBG) {
726            Rlog.d(LOG_TAG, "End conference(" +heldCall + ")");
727            Rlog.d(LOG_TAG, toString());
728        }
729
730    }
731
732    /**
733     * Initiate a new voice connection. This happens asynchronously, so you
734     * cannot assume the audio path is connected (or a call index has been
735     * assigned) until PhoneStateChanged notification has occurred.
736     *
737     * @exception CallStateException if a new outgoing call is not currently
738     * possible because no more call slots exist or a call exists that is
739     * dialing, alerting, ringing, or waiting.  Other errors are
740     * handled asynchronously.
741     */
742    public Connection dial(Phone phone, String dialString) throws CallStateException {
743        Phone basePhone = getPhoneBase(phone);
744        Connection result;
745
746        if (VDBG) {
747            Rlog.d(LOG_TAG, " dial(" + basePhone + ", "+ dialString + ")");
748            Rlog.d(LOG_TAG, toString());
749        }
750
751        if (!canDial(phone)) {
752            throw new CallStateException("cannot dial in current state");
753        }
754
755        if ( hasActiveFgCall() ) {
756            Phone activePhone = getActiveFgCall().getPhone();
757            boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
758
759            if (DBG) {
760                Rlog.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
761            }
762
763            if (activePhone != basePhone) {
764                if (hasBgCall) {
765                    Rlog.d(LOG_TAG, "Hangup");
766                    getActiveFgCall().hangup();
767                } else {
768                    Rlog.d(LOG_TAG, "Switch");
769                    activePhone.switchHoldingAndActive();
770                }
771            }
772        }
773
774        result = basePhone.dial(dialString);
775
776        if (VDBG) {
777            Rlog.d(LOG_TAG, "End dial(" + basePhone + ", "+ dialString + ")");
778            Rlog.d(LOG_TAG, toString());
779        }
780
781        return result;
782    }
783
784    /**
785     * Initiate a new voice connection. This happens asynchronously, so you
786     * cannot assume the audio path is connected (or a call index has been
787     * assigned) until PhoneStateChanged notification has occurred.
788     *
789     * @exception CallStateException if a new outgoing call is not currently
790     * possible because no more call slots exist or a call exists that is
791     * dialing, alerting, ringing, or waiting.  Other errors are
792     * handled asynchronously.
793     */
794    public Connection dial(Phone phone, String dialString, UUSInfo uusInfo) throws CallStateException {
795        return phone.dial(dialString, uusInfo);
796    }
797
798    /**
799     * clear disconnect connection for each phone
800     */
801    public void clearDisconnected() {
802        for(Phone phone : mPhones) {
803            phone.clearDisconnected();
804        }
805    }
806
807    /**
808     * Phone can make a call only if ALL of the following are true:
809     *        - Phone is not powered off
810     *        - There's no incoming or waiting call
811     *        - The foreground call is ACTIVE or IDLE or DISCONNECTED.
812     *          (We mainly need to make sure it *isn't* DIALING or ALERTING.)
813     * @param phone
814     * @return true if the phone can make a new call
815     */
816    private boolean canDial(Phone phone) {
817        int serviceState = phone.getServiceState().getState();
818        boolean hasRingingCall = hasActiveRingingCall();
819        Call.State fgCallState = getActiveFgCallState();
820
821        boolean result = (serviceState != ServiceState.STATE_POWER_OFF
822                && !hasRingingCall
823                && ((fgCallState == Call.State.ACTIVE)
824                    || (fgCallState == Call.State.IDLE)
825                    || (fgCallState == Call.State.DISCONNECTED)));
826
827        if (result == false) {
828            Rlog.d(LOG_TAG, "canDial serviceState=" + serviceState
829                            + " hasRingingCall=" + hasRingingCall
830                            + " fgCallState=" + fgCallState);
831        }
832        return result;
833    }
834
835    /**
836     * Whether or not the phone can do explicit call transfer in the current
837     * phone state--that is, one call holding and one call active.
838     * @return true if the phone can do explicit call transfer; false otherwise.
839     */
840    public boolean canTransfer(Call heldCall) {
841        Phone activePhone = null;
842        Phone heldPhone = null;
843
844        if (hasActiveFgCall()) {
845            activePhone = getActiveFgCall().getPhone();
846        }
847
848        if (heldCall != null) {
849            heldPhone = heldCall.getPhone();
850        }
851
852        return (heldPhone == activePhone && activePhone.canTransfer());
853    }
854
855    /**
856     * Connects the held call and active call
857     * Disconnects the subscriber from both calls
858     *
859     * Explicit Call Transfer occurs asynchronously
860     * and may fail. Final notification occurs via
861     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
862     * java.lang.Object) registerForPreciseCallStateChanged()}.
863     *
864     * @exception CallStateException if canTransfer() would return false.
865     * In these cases, this operation may not be performed.
866     */
867    public void explicitCallTransfer(Call heldCall) throws CallStateException {
868        if (VDBG) {
869            Rlog.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")");
870            Rlog.d(LOG_TAG, toString());
871        }
872
873        if (canTransfer(heldCall)) {
874            heldCall.getPhone().explicitCallTransfer();
875        }
876
877        if (VDBG) {
878            Rlog.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")");
879            Rlog.d(LOG_TAG, toString());
880        }
881
882    }
883
884    /**
885     * Returns a list of MMI codes that are pending for a phone. (They have initiated
886     * but have not yet completed).
887     * Presently there is only ever one.
888     *
889     * Use <code>registerForMmiInitiate</code>
890     * and <code>registerForMmiComplete</code> for change notification.
891     * @return null if phone doesn't have or support mmi code
892     */
893    public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
894        Rlog.e(LOG_TAG, "getPendingMmiCodes not implemented");
895        return null;
896    }
897
898    /**
899     * Sends user response to a USSD REQUEST message.  An MmiCode instance
900     * representing this response is sent to handlers registered with
901     * registerForMmiInitiate.
902     *
903     * @param ussdMessge    Message to send in the response.
904     * @return false if phone doesn't support ussd service
905     */
906    public boolean sendUssdResponse(Phone phone, String ussdMessge) {
907        Rlog.e(LOG_TAG, "sendUssdResponse not implemented");
908        return false;
909    }
910
911    /**
912     * Mutes or unmutes the microphone for the active call. The microphone
913     * is automatically unmuted if a call is answered, dialed, or resumed
914     * from a holding state.
915     *
916     * @param muted true to mute the microphone,
917     * false to activate the microphone.
918     */
919
920    public void setMute(boolean muted) {
921        if (VDBG) {
922            Rlog.d(LOG_TAG, " setMute(" + muted + ")");
923            Rlog.d(LOG_TAG, toString());
924        }
925
926        if (hasActiveFgCall()) {
927            getActiveFgCall().getPhone().setMute(muted);
928        }
929
930        if (VDBG) {
931            Rlog.d(LOG_TAG, "End setMute(" + muted + ")");
932            Rlog.d(LOG_TAG, toString());
933        }
934    }
935
936    /**
937     * Gets current mute status. Use
938     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
939     * java.lang.Object) registerForPreciseCallStateChanged()}
940     * as a change notifcation, although presently phone state changed is not
941     * fired when setMute() is called.
942     *
943     * @return true is muting, false is unmuting
944     */
945    public boolean getMute() {
946        if (hasActiveFgCall()) {
947            return getActiveFgCall().getPhone().getMute();
948        } else if (hasActiveBgCall()) {
949            return getFirstActiveBgCall().getPhone().getMute();
950        }
951        return false;
952    }
953
954    /**
955     * Enables or disables echo suppression.
956     */
957    public void setEchoSuppressionEnabled(boolean enabled) {
958        if (VDBG) {
959            Rlog.d(LOG_TAG, " setEchoSuppression(" + enabled + ")");
960            Rlog.d(LOG_TAG, toString());
961        }
962
963        if (hasActiveFgCall()) {
964            getActiveFgCall().getPhone().setEchoSuppressionEnabled(enabled);
965        }
966
967        if (VDBG) {
968            Rlog.d(LOG_TAG, "End setEchoSuppression(" + enabled + ")");
969            Rlog.d(LOG_TAG, toString());
970        }
971    }
972
973    /**
974     * Play a DTMF tone on the active call.
975     *
976     * @param c should be one of 0-9, '*' or '#'. Other values will be
977     * silently ignored.
978     * @return false if no active call or the active call doesn't support
979     *         dtmf tone
980     */
981    public boolean sendDtmf(char c) {
982        boolean result = false;
983
984        if (VDBG) {
985            Rlog.d(LOG_TAG, " sendDtmf(" + c + ")");
986            Rlog.d(LOG_TAG, toString());
987        }
988
989        if (hasActiveFgCall()) {
990            getActiveFgCall().getPhone().sendDtmf(c);
991            result = true;
992        }
993
994        if (VDBG) {
995            Rlog.d(LOG_TAG, "End sendDtmf(" + c + ")");
996            Rlog.d(LOG_TAG, toString());
997        }
998        return result;
999    }
1000
1001    /**
1002     * Start to paly a DTMF tone on the active call.
1003     * or there is a playing DTMF tone.
1004     * @param c should be one of 0-9, '*' or '#'. Other values will be
1005     * silently ignored.
1006     *
1007     * @return false if no active call or the active call doesn't support
1008     *         dtmf tone
1009     */
1010    public boolean startDtmf(char c) {
1011        boolean result = false;
1012
1013        if (VDBG) {
1014            Rlog.d(LOG_TAG, " startDtmf(" + c + ")");
1015            Rlog.d(LOG_TAG, toString());
1016        }
1017
1018        if (hasActiveFgCall()) {
1019            getActiveFgCall().getPhone().startDtmf(c);
1020            result = true;
1021        }
1022
1023        if (VDBG) {
1024            Rlog.d(LOG_TAG, "End startDtmf(" + c + ")");
1025            Rlog.d(LOG_TAG, toString());
1026        }
1027
1028        return result;
1029    }
1030
1031    /**
1032     * Stop the playing DTMF tone. Ignored if there is no playing DTMF
1033     * tone or no active call.
1034     */
1035    public void stopDtmf() {
1036        if (VDBG) {
1037            Rlog.d(LOG_TAG, " stopDtmf()" );
1038            Rlog.d(LOG_TAG, toString());
1039        }
1040
1041        if (hasActiveFgCall()) getFgPhone().stopDtmf();
1042
1043        if (VDBG) {
1044            Rlog.d(LOG_TAG, "End stopDtmf()");
1045            Rlog.d(LOG_TAG, toString());
1046        }
1047    }
1048
1049    /**
1050     * send burst DTMF tone, it can send the string as single character or multiple character
1051     * ignore if there is no active call or not valid digits string.
1052     * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
1053     * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
1054     * this api can send single character and multiple character, also, this api has response
1055     * back to caller.
1056     *
1057     * @param dtmfString is string representing the dialing digit(s) in the active call
1058     * @param on the DTMF ON length in milliseconds, or 0 for default
1059     * @param off the DTMF OFF length in milliseconds, or 0 for default
1060     * @param onComplete is the callback message when the action is processed by BP
1061     *
1062     */
1063    public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1064        if (hasActiveFgCall()) {
1065            getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
1066            return true;
1067        }
1068        return false;
1069    }
1070
1071    /**
1072     * Notifies when a voice connection has disconnected, either due to local
1073     * or remote hangup or error.
1074     *
1075     *  Messages received from this will have the following members:<p>
1076     *  <ul><li>Message.obj will be an AsyncResult</li>
1077     *  <li>AsyncResult.userObj = obj</li>
1078     *  <li>AsyncResult.result = a Connection object that is
1079     *  no longer connected.</li></ul>
1080     */
1081    public void registerForDisconnect(Handler h, int what, Object obj) {
1082        mDisconnectRegistrants.addUnique(h, what, obj);
1083    }
1084
1085    /**
1086     * Unregisters for voice disconnection notification.
1087     * Extraneous calls are tolerated silently
1088     */
1089    public void unregisterForDisconnect(Handler h){
1090        mDisconnectRegistrants.remove(h);
1091    }
1092
1093    /**
1094     * Register for getting notifications for change in the Call State {@link Call.State}
1095     * This is called PreciseCallState because the call state is more precise than what
1096     * can be obtained using the {@link PhoneStateListener}
1097     *
1098     * Resulting events will have an AsyncResult in <code>Message.obj</code>.
1099     * AsyncResult.userData will be set to the obj argument here.
1100     * The <em>h</em> parameter is held only by a weak reference.
1101     */
1102    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
1103        mPreciseCallStateRegistrants.addUnique(h, what, obj);
1104    }
1105
1106    /**
1107     * Unregisters for voice call state change notifications.
1108     * Extraneous calls are tolerated silently.
1109     */
1110    public void unregisterForPreciseCallStateChanged(Handler h){
1111        mPreciseCallStateRegistrants.remove(h);
1112    }
1113
1114    /**
1115     * Notifies when a previously untracked non-ringing/waiting connection has appeared.
1116     * This is likely due to some other entity (eg, SIM card application) initiating a call.
1117     */
1118    public void registerForUnknownConnection(Handler h, int what, Object obj){
1119        mUnknownConnectionRegistrants.addUnique(h, what, obj);
1120    }
1121
1122    /**
1123     * Unregisters for unknown connection notifications.
1124     */
1125    public void unregisterForUnknownConnection(Handler h){
1126        mUnknownConnectionRegistrants.remove(h);
1127    }
1128
1129
1130    /**
1131     * Notifies when a new ringing or waiting connection has appeared.<p>
1132     *
1133     *  Messages received from this:
1134     *  Message.obj will be an AsyncResult
1135     *  AsyncResult.userObj = obj
1136     *  AsyncResult.result = a Connection. <p>
1137     *  Please check Connection.isRinging() to make sure the Connection
1138     *  has not dropped since this message was posted.
1139     *  If Connection.isRinging() is true, then
1140     *   Connection.getCall() == Phone.getRingingCall()
1141     */
1142    public void registerForNewRingingConnection(Handler h, int what, Object obj){
1143        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
1144    }
1145
1146    /**
1147     * Unregisters for new ringing connection notification.
1148     * Extraneous calls are tolerated silently
1149     */
1150
1151    public void unregisterForNewRingingConnection(Handler h){
1152        mNewRingingConnectionRegistrants.remove(h);
1153    }
1154
1155    /**
1156     * Notifies when an incoming call rings.<p>
1157     *
1158     *  Messages received from this:
1159     *  Message.obj will be an AsyncResult
1160     *  AsyncResult.userObj = obj
1161     *  AsyncResult.result = a Connection. <p>
1162     */
1163    public void registerForIncomingRing(Handler h, int what, Object obj){
1164        mIncomingRingRegistrants.addUnique(h, what, obj);
1165    }
1166
1167    /**
1168     * Unregisters for ring notification.
1169     * Extraneous calls are tolerated silently
1170     */
1171
1172    public void unregisterForIncomingRing(Handler h){
1173        mIncomingRingRegistrants.remove(h);
1174    }
1175
1176    /**
1177     * Notifies when out-band ringback tone is needed.<p>
1178     *
1179     *  Messages received from this:
1180     *  Message.obj will be an AsyncResult
1181     *  AsyncResult.userObj = obj
1182     *  AsyncResult.result = boolean, true to start play ringback tone
1183     *                       and false to stop. <p>
1184     */
1185    public void registerForRingbackTone(Handler h, int what, Object obj){
1186        mRingbackToneRegistrants.addUnique(h, what, obj);
1187    }
1188
1189    /**
1190     * Unregisters for ringback tone notification.
1191     */
1192
1193    public void unregisterForRingbackTone(Handler h){
1194        mRingbackToneRegistrants.remove(h);
1195    }
1196
1197    /**
1198     * Registers the handler to reset the uplink mute state to get
1199     * uplink audio.
1200     */
1201    public void registerForResendIncallMute(Handler h, int what, Object obj){
1202        mResendIncallMuteRegistrants.addUnique(h, what, obj);
1203    }
1204
1205    /**
1206     * Unregisters for resend incall mute notifications.
1207     */
1208    public void unregisterForResendIncallMute(Handler h){
1209        mResendIncallMuteRegistrants.remove(h);
1210    }
1211
1212    /**
1213     * Register for notifications of initiation of a new MMI code request.
1214     * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
1215     *
1216     * Example: If Phone.dial is called with "*#31#", then the app will
1217     * be notified here.<p>
1218     *
1219     * The returned <code>Message.obj</code> will contain an AsyncResult.
1220     *
1221     * <code>obj.result</code> will be an "MmiCode" object.
1222     */
1223    public void registerForMmiInitiate(Handler h, int what, Object obj){
1224        mMmiInitiateRegistrants.addUnique(h, what, obj);
1225    }
1226
1227    /**
1228     * Unregisters for new MMI initiate notification.
1229     * Extraneous calls are tolerated silently
1230     */
1231    public void unregisterForMmiInitiate(Handler h){
1232        mMmiInitiateRegistrants.remove(h);
1233    }
1234
1235    /**
1236     * Register for notifications that an MMI request has completed
1237     * its network activity and is in its final state. This may mean a state
1238     * of COMPLETE, FAILED, or CANCELLED.
1239     *
1240     * <code>Message.obj</code> will contain an AsyncResult.
1241     * <code>obj.result</code> will be an "MmiCode" object
1242     */
1243    public void registerForMmiComplete(Handler h, int what, Object obj){
1244        mMmiCompleteRegistrants.addUnique(h, what, obj);
1245    }
1246
1247    /**
1248     * Unregisters for MMI complete notification.
1249     * Extraneous calls are tolerated silently
1250     */
1251    public void unregisterForMmiComplete(Handler h){
1252        mMmiCompleteRegistrants.remove(h);
1253    }
1254
1255    /**
1256     * Registration point for Ecm timer reset
1257     * @param h handler to notify
1258     * @param what user-defined message code
1259     * @param obj placed in Message.obj
1260     */
1261    public void registerForEcmTimerReset(Handler h, int what, Object obj){
1262        mEcmTimerResetRegistrants.addUnique(h, what, obj);
1263    }
1264
1265    /**
1266     * Unregister for notification for Ecm timer reset
1267     * @param h Handler to be removed from the registrant list.
1268     */
1269    public void unregisterForEcmTimerReset(Handler h){
1270        mEcmTimerResetRegistrants.remove(h);
1271    }
1272
1273    /**
1274     * Register for ServiceState changed.
1275     * Message.obj will contain an AsyncResult.
1276     * AsyncResult.result will be a ServiceState instance
1277     */
1278    public void registerForServiceStateChanged(Handler h, int what, Object obj){
1279        mServiceStateChangedRegistrants.addUnique(h, what, obj);
1280    }
1281
1282    /**
1283     * Unregisters for ServiceStateChange notification.
1284     * Extraneous calls are tolerated silently
1285     */
1286    public void unregisterForServiceStateChanged(Handler h){
1287        mServiceStateChangedRegistrants.remove(h);
1288    }
1289
1290    /**
1291     * Register for notifications when a supplementary service attempt fails.
1292     * Message.obj will contain an AsyncResult.
1293     *
1294     * @param h Handler that receives the notification message.
1295     * @param what User-defined message code.
1296     * @param obj User object.
1297     */
1298    public void registerForSuppServiceFailed(Handler h, int what, Object obj){
1299        mSuppServiceFailedRegistrants.addUnique(h, what, obj);
1300    }
1301
1302    /**
1303     * Unregister for notifications when a supplementary service attempt fails.
1304     * Extraneous calls are tolerated silently
1305     *
1306     * @param h Handler to be removed from the registrant list.
1307     */
1308    public void unregisterForSuppServiceFailed(Handler h){
1309        mSuppServiceFailedRegistrants.remove(h);
1310    }
1311
1312    /**
1313     * Register for notifications when a sInCall VoicePrivacy is enabled
1314     *
1315     * @param h Handler that receives the notification message.
1316     * @param what User-defined message code.
1317     * @param obj User object.
1318     */
1319    public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
1320        mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
1321    }
1322
1323    /**
1324     * Unregister for notifications when a sInCall VoicePrivacy is enabled
1325     *
1326     * @param h Handler to be removed from the registrant list.
1327     */
1328    public void unregisterForInCallVoicePrivacyOn(Handler h){
1329        mInCallVoicePrivacyOnRegistrants.remove(h);
1330    }
1331
1332    /**
1333     * Register for notifications when a sInCall VoicePrivacy is disabled
1334     *
1335     * @param h Handler that receives the notification message.
1336     * @param what User-defined message code.
1337     * @param obj User object.
1338     */
1339    public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
1340        mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
1341    }
1342
1343    /**
1344     * Unregister for notifications when a sInCall VoicePrivacy is disabled
1345     *
1346     * @param h Handler to be removed from the registrant list.
1347     */
1348    public void unregisterForInCallVoicePrivacyOff(Handler h){
1349        mInCallVoicePrivacyOffRegistrants.remove(h);
1350    }
1351
1352    /**
1353     * Register for notifications when CDMA call waiting comes
1354     *
1355     * @param h Handler that receives the notification message.
1356     * @param what User-defined message code.
1357     * @param obj User object.
1358     */
1359    public void registerForCallWaiting(Handler h, int what, Object obj){
1360        mCallWaitingRegistrants.addUnique(h, what, obj);
1361    }
1362
1363    /**
1364     * Unregister for notifications when CDMA Call waiting comes
1365     * @param h Handler to be removed from the registrant list.
1366     */
1367    public void unregisterForCallWaiting(Handler h){
1368        mCallWaitingRegistrants.remove(h);
1369    }
1370
1371
1372    /**
1373     * Register for signal information notifications from the network.
1374     * Message.obj will contain an AsyncResult.
1375     * AsyncResult.result will be a SuppServiceNotification instance.
1376     *
1377     * @param h Handler that receives the notification message.
1378     * @param what User-defined message code.
1379     * @param obj User object.
1380     */
1381
1382    public void registerForSignalInfo(Handler h, int what, Object obj){
1383        mSignalInfoRegistrants.addUnique(h, what, obj);
1384    }
1385
1386    /**
1387     * Unregisters for signal information notifications.
1388     * Extraneous calls are tolerated silently
1389     *
1390     * @param h Handler to be removed from the registrant list.
1391     */
1392    public void unregisterForSignalInfo(Handler h){
1393        mSignalInfoRegistrants.remove(h);
1394    }
1395
1396    /**
1397     * Register for display information notifications from the network.
1398     * Message.obj will contain an AsyncResult.
1399     * AsyncResult.result will be a SuppServiceNotification instance.
1400     *
1401     * @param h Handler that receives the notification message.
1402     * @param what User-defined message code.
1403     * @param obj User object.
1404     */
1405    public void registerForDisplayInfo(Handler h, int what, Object obj){
1406        mDisplayInfoRegistrants.addUnique(h, what, obj);
1407    }
1408
1409    /**
1410     * Unregisters for display information notifications.
1411     * Extraneous calls are tolerated silently
1412     *
1413     * @param h Handler to be removed from the registrant list.
1414     */
1415    public void unregisterForDisplayInfo(Handler h) {
1416        mDisplayInfoRegistrants.remove(h);
1417    }
1418
1419    /**
1420     * Register for notifications when CDMA OTA Provision status change
1421     *
1422     * @param h Handler that receives the notification message.
1423     * @param what User-defined message code.
1424     * @param obj User object.
1425     */
1426    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){
1427        mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
1428    }
1429
1430    /**
1431     * Unregister for notifications when CDMA OTA Provision status change
1432     * @param h Handler to be removed from the registrant list.
1433     */
1434    public void unregisterForCdmaOtaStatusChange(Handler h){
1435        mCdmaOtaStatusChangeRegistrants.remove(h);
1436    }
1437
1438    /**
1439     * Registration point for subscription info ready
1440     * @param h handler to notify
1441     * @param what what code of message when delivered
1442     * @param obj placed in Message.obj
1443     */
1444    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){
1445        mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
1446    }
1447
1448    /**
1449     * Unregister for notifications for subscription info
1450     * @param h Handler to be removed from the registrant list.
1451     */
1452    public void unregisterForSubscriptionInfoReady(Handler h){
1453        mSubscriptionInfoReadyRegistrants.remove(h);
1454    }
1455
1456    /**
1457     * Sets an event to be fired when the telephony system processes
1458     * a post-dial character on an outgoing call.<p>
1459     *
1460     * Messages of type <code>what</code> will be sent to <code>h</code>.
1461     * The <code>obj</code> field of these Message's will be instances of
1462     * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
1463     * a Connection object.<p>
1464     *
1465     * Message.arg1 will be the post dial character being processed,
1466     * or 0 ('\0') if end of string.<p>
1467     *
1468     * If Connection.getPostDialState() == WAIT,
1469     * the application must call
1470     * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
1471     * Connection.proceedAfterWaitChar()} or
1472     * {@link com.android.internal.telephony.Connection#cancelPostDial()
1473     * Connection.cancelPostDial()}
1474     * for the telephony system to continue playing the post-dial
1475     * DTMF sequence.<p>
1476     *
1477     * If Connection.getPostDialState() == WILD,
1478     * the application must call
1479     * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
1480     * Connection.proceedAfterWildChar()}
1481     * or
1482     * {@link com.android.internal.telephony.Connection#cancelPostDial()
1483     * Connection.cancelPostDial()}
1484     * for the telephony system to continue playing the
1485     * post-dial DTMF sequence.<p>
1486     *
1487     */
1488    public void registerForPostDialCharacter(Handler h, int what, Object obj){
1489        mPostDialCharacterRegistrants.addUnique(h, what, obj);
1490    }
1491
1492    public void unregisterForPostDialCharacter(Handler h){
1493        mPostDialCharacterRegistrants.remove(h);
1494    }
1495
1496    /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
1497     * 1. APIs to access list of calls
1498     * 2. APIs to check if any active call, which has connection other than
1499     * disconnected ones, pleaser refer to Call.isIdle()
1500     * 3. APIs to return first active call
1501     * 4. APIs to return the connections of first active call
1502     * 5. APIs to return other property of first active call
1503     */
1504
1505    /**
1506     * @return list of all ringing calls
1507     */
1508    public List<Call> getRingingCalls() {
1509        return Collections.unmodifiableList(mRingingCalls);
1510    }
1511
1512    /**
1513     * @return list of all foreground calls
1514     */
1515    public List<Call> getForegroundCalls() {
1516        return Collections.unmodifiableList(mForegroundCalls);
1517    }
1518
1519    /**
1520     * @return list of all background calls
1521     */
1522    public List<Call> getBackgroundCalls() {
1523        return Collections.unmodifiableList(mBackgroundCalls);
1524    }
1525
1526    /**
1527     * Return true if there is at least one active foreground call
1528     */
1529    public boolean hasActiveFgCall() {
1530        return (getFirstActiveCall(mForegroundCalls) != null);
1531    }
1532
1533    /**
1534     * Return true if there is at least one active background call
1535     */
1536    public boolean hasActiveBgCall() {
1537        // TODO since hasActiveBgCall may get called often
1538        // better to cache it to improve performance
1539        return (getFirstActiveCall(mBackgroundCalls) != null);
1540    }
1541
1542    /**
1543     * Return true if there is at least one active ringing call
1544     *
1545     */
1546    public boolean hasActiveRingingCall() {
1547        return (getFirstActiveCall(mRingingCalls) != null);
1548    }
1549
1550    /**
1551     * return the active foreground call from foreground calls
1552     *
1553     * Active call means the call is NOT in Call.State.IDLE
1554     *
1555     * 1. If there is active foreground call, return it
1556     * 2. If there is no active foreground call, return the
1557     *    foreground call associated with default phone, which state is IDLE.
1558     * 3. If there is no phone registered at all, return null.
1559     *
1560     */
1561    public Call getActiveFgCall() {
1562        Call call = getFirstNonIdleCall(mForegroundCalls);
1563        if (call == null) {
1564            call = (mDefaultPhone == null)
1565                    ? null
1566                    : mDefaultPhone.getForegroundCall();
1567        }
1568        return call;
1569    }
1570
1571    // Returns the first call that is not in IDLE state. If both active calls
1572    // and disconnecting/disconnected calls exist, return the first active call.
1573    private Call getFirstNonIdleCall(List<Call> calls) {
1574        Call result = null;
1575        for (Call call : calls) {
1576            if (!call.isIdle()) {
1577                return call;
1578            } else if (call.getState() != Call.State.IDLE) {
1579                if (result == null) result = call;
1580            }
1581        }
1582        return result;
1583    }
1584
1585    /**
1586     * return one active background call from background calls
1587     *
1588     * Active call means the call is NOT idle defined by Call.isIdle()
1589     *
1590     * 1. If there is only one active background call, return it
1591     * 2. If there is more than one active background call, return the first one
1592     * 3. If there is no active background call, return the background call
1593     *    associated with default phone, which state is IDLE.
1594     * 4. If there is no background call at all, return null.
1595     *
1596     * Complete background calls list can be get by getBackgroundCalls()
1597     */
1598    public Call getFirstActiveBgCall() {
1599        Call call = getFirstNonIdleCall(mBackgroundCalls);
1600        if (call == null) {
1601            call = (mDefaultPhone == null)
1602                    ? null
1603                    : mDefaultPhone.getBackgroundCall();
1604        }
1605        return call;
1606    }
1607
1608    /**
1609     * return one active ringing call from ringing calls
1610     *
1611     * Active call means the call is NOT idle defined by Call.isIdle()
1612     *
1613     * 1. If there is only one active ringing call, return it
1614     * 2. If there is more than one active ringing call, return the first one
1615     * 3. If there is no active ringing call, return the ringing call
1616     *    associated with default phone, which state is IDLE.
1617     * 4. If there is no ringing call at all, return null.
1618     *
1619     * Complete ringing calls list can be get by getRingingCalls()
1620     */
1621    public Call getFirstActiveRingingCall() {
1622        Call call = getFirstNonIdleCall(mRingingCalls);
1623        if (call == null) {
1624            call = (mDefaultPhone == null)
1625                    ? null
1626                    : mDefaultPhone.getRingingCall();
1627        }
1628        return call;
1629    }
1630
1631    /**
1632     * @return the state of active foreground call
1633     * return IDLE if there is no active foreground call
1634     */
1635    public Call.State getActiveFgCallState() {
1636        Call fgCall = getActiveFgCall();
1637
1638        if (fgCall != null) {
1639            return fgCall.getState();
1640        }
1641
1642        return Call.State.IDLE;
1643    }
1644
1645    /**
1646     * @return the connections of active foreground call
1647     * return empty list if there is no active foreground call
1648     */
1649    public List<Connection> getFgCallConnections() {
1650        Call fgCall = getActiveFgCall();
1651        if ( fgCall != null) {
1652            return fgCall.getConnections();
1653        }
1654        return mEmptyConnections;
1655    }
1656
1657    /**
1658     * @return the connections of active background call
1659     * return empty list if there is no active background call
1660     */
1661    public List<Connection> getBgCallConnections() {
1662        Call bgCall = getFirstActiveBgCall();
1663        if ( bgCall != null) {
1664            return bgCall.getConnections();
1665        }
1666        return mEmptyConnections;
1667    }
1668
1669    /**
1670     * @return the latest connection of active foreground call
1671     * return null if there is no active foreground call
1672     */
1673    public Connection getFgCallLatestConnection() {
1674        Call fgCall = getActiveFgCall();
1675        if ( fgCall != null) {
1676            return fgCall.getLatestConnection();
1677        }
1678        return null;
1679    }
1680
1681    /**
1682     * @return true if there is at least one Foreground call in disconnected state
1683     */
1684    public boolean hasDisconnectedFgCall() {
1685        return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
1686    }
1687
1688    /**
1689     * @return true if there is at least one background call in disconnected state
1690     */
1691    public boolean hasDisconnectedBgCall() {
1692        return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
1693    }
1694
1695    /**
1696     * @return the first active call from a call list
1697     */
1698    private  Call getFirstActiveCall(ArrayList<Call> calls) {
1699        for (Call call : calls) {
1700            if (!call.isIdle()) {
1701                return call;
1702            }
1703        }
1704        return null;
1705    }
1706
1707    /**
1708     * @return the first call in a the Call.state from a call list
1709     */
1710    private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
1711        for (Call call : calls) {
1712            if (call.getState() == state) {
1713                return call;
1714            }
1715        }
1716        return null;
1717    }
1718
1719
1720    private boolean hasMoreThanOneRingingCall() {
1721        int count = 0;
1722        for (Call call : mRingingCalls) {
1723            if (call.getState().isRinging()) {
1724                if (++count > 1) return true;
1725            }
1726        }
1727        return false;
1728    }
1729
1730    private Handler mHandler = new Handler() {
1731
1732        @Override
1733        public void handleMessage(Message msg) {
1734
1735            switch (msg.what) {
1736                case EVENT_DISCONNECT:
1737                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_DISCONNECT)");
1738                    mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1739                    break;
1740                case EVENT_PRECISE_CALL_STATE_CHANGED:
1741                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)");
1742                    mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1743                    break;
1744                case EVENT_NEW_RINGING_CONNECTION:
1745                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
1746                    if (getActiveFgCallState().isDialing() || hasMoreThanOneRingingCall()) {
1747                        Connection c = (Connection) ((AsyncResult) msg.obj).result;
1748                        try {
1749                            Rlog.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
1750                            c.getCall().hangup();
1751                        } catch (CallStateException e) {
1752                            Rlog.w(LOG_TAG, "new ringing connection", e);
1753                        }
1754                    } else {
1755                        mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1756                    }
1757                    break;
1758                case EVENT_UNKNOWN_CONNECTION:
1759                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_UNKNOWN_CONNECTION)");
1760                    mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1761                    break;
1762                case EVENT_INCOMING_RING:
1763                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)");
1764                    // The event may come from RIL who's not aware of an ongoing fg call
1765                    if (!hasActiveFgCall()) {
1766                        mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1767                    }
1768                    break;
1769                case EVENT_RINGBACK_TONE:
1770                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RINGBACK_TONE)");
1771                    mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1772                    break;
1773                case EVENT_IN_CALL_VOICE_PRIVACY_ON:
1774                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_ON)");
1775                    mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1776                    break;
1777                case EVENT_IN_CALL_VOICE_PRIVACY_OFF:
1778                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_OFF)");
1779                    mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1780                    break;
1781                case EVENT_CALL_WAITING:
1782                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_CALL_WAITING)");
1783                    mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1784                    break;
1785                case EVENT_DISPLAY_INFO:
1786                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_DISPLAY_INFO)");
1787                    mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1788                    break;
1789                case EVENT_SIGNAL_INFO:
1790                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SIGNAL_INFO)");
1791                    mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1792                    break;
1793                case EVENT_CDMA_OTA_STATUS_CHANGE:
1794                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_CDMA_OTA_STATUS_CHANGE)");
1795                    mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1796                    break;
1797                case EVENT_RESEND_INCALL_MUTE:
1798                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_RESEND_INCALL_MUTE)");
1799                    mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1800                    break;
1801                case EVENT_MMI_INITIATE:
1802                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_INITIATE)");
1803                    mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1804                    break;
1805                case EVENT_MMI_COMPLETE:
1806                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
1807                    mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1808                    break;
1809                case EVENT_ECM_TIMER_RESET:
1810                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_ECM_TIMER_RESET)");
1811                    mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1812                    break;
1813                case EVENT_SUBSCRIPTION_INFO_READY:
1814                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SUBSCRIPTION_INFO_READY)");
1815                    mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1816                    break;
1817                case EVENT_SUPP_SERVICE_FAILED:
1818                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SUPP_SERVICE_FAILED)");
1819                    mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1820                    break;
1821                case EVENT_SERVICE_STATE_CHANGED:
1822                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_SERVICE_STATE_CHANGED)");
1823                    mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1824                    break;
1825                case EVENT_POST_DIAL_CHARACTER:
1826                    // we need send the character that is being processed in msg.arg1
1827                    // so can't use notifyRegistrants()
1828                    if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_POST_DIAL_CHARACTER)");
1829                    for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
1830                        Message notifyMsg;
1831                        notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
1832                        notifyMsg.obj = msg.obj;
1833                        notifyMsg.arg1 = msg.arg1;
1834                        notifyMsg.sendToTarget();
1835                    }
1836                    break;
1837            }
1838        }
1839    };
1840
1841    @Override
1842    public String toString() {
1843        Call call;
1844        StringBuilder b = new StringBuilder();
1845
1846        b.append("CallManager {");
1847        b.append("\nstate = " + getState());
1848        call = getActiveFgCall();
1849        b.append("\n- Foreground: " + getActiveFgCallState());
1850        b.append(" from " + call.getPhone());
1851        b.append("\n  Conn: ").append(getFgCallConnections());
1852        call = getFirstActiveBgCall();
1853        b.append("\n- Background: " + call.getState());
1854        b.append(" from " + call.getPhone());
1855        b.append("\n  Conn: ").append(getBgCallConnections());
1856        call = getFirstActiveRingingCall();
1857        b.append("\n- Ringing: " +call.getState());
1858        b.append(" from " + call.getPhone());
1859
1860        for (Phone phone : getAllPhones()) {
1861            if (phone != null) {
1862                b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
1863                        + ", state = " + phone.getState());
1864                call = phone.getForegroundCall();
1865                b.append("\n- Foreground: ").append(call);
1866                call = phone.getBackgroundCall();
1867                b.append(" Background: ").append(call);
1868                call = phone.getRingingCall();
1869                b.append(" Ringing: ").append(call);
1870            }
1871        }
1872        b.append("\n}");
1873        return b.toString();
1874    }
1875}
1876