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