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.util.Log;
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> emptyConnections = 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                Log.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                Log.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) Log.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) Log.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) Log.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            Log.d(LOG_TAG, "acceptCall(" +ringingCall + " from " + ringingCall.getPhone() + ")");
522            Log.d(LOG_TAG, this.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                Log.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            Log.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            Log.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                Log.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            Log.d(LOG_TAG, "End acceptCall(" +ringingCall + ")");
564            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, "rejectCall(" +ringingCall + ")");
580            Log.d(LOG_TAG, this.toString());
581        }
582
583        Phone ringingPhone = ringingCall.getPhone();
584
585        ringingPhone.rejectCall();
586
587        if (VDBG) {
588            Log.d(LOG_TAG, "End rejectCall(" +ringingCall + ")");
589            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, "switchHoldingAndActive(" +heldCall + ")");
617            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, "End switchHoldingAndActive(" +heldCall + ")");
638            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, "hangupForegroundResumeBackground(" +heldCall + ")");
656            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, "End hangupForegroundResumeBackground(" +heldCall + ")");
675            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, "conference(" +heldCall + ")");
712            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, "End conference(" +heldCall + ")");
727            Log.d(LOG_TAG, this.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            Log.d(LOG_TAG, " dial(" + basePhone + ", "+ dialString + ")");
748            Log.d(LOG_TAG, this.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                Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone));
761            }
762
763            if (activePhone != basePhone) {
764                if (hasBgCall) {
765                    Log.d(LOG_TAG, "Hangup");
766                    getActiveFgCall().hangup();
767                } else {
768                    Log.d(LOG_TAG, "Switch");
769                    activePhone.switchHoldingAndActive();
770                }
771            }
772        }
773
774        result = basePhone.dial(dialString);
775
776        if (VDBG) {
777            Log.d(LOG_TAG, "End dial(" + basePhone + ", "+ dialString + ")");
778            Log.d(LOG_TAG, this.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     *        - There's available call slot in either foreground or background
812     *        - The foreground call is ACTIVE or IDLE or DISCONNECTED.
813     *          (We mainly need to make sure it *isn't* DIALING or ALERTING.)
814     * @param phone
815     * @return true if the phone can make a new call
816     */
817    private boolean canDial(Phone phone) {
818        int serviceState = phone.getServiceState().getState();
819        boolean hasRingingCall = hasActiveRingingCall();
820        boolean hasActiveCall = hasActiveFgCall();
821        boolean hasHoldingCall = hasActiveBgCall();
822        boolean allLinesTaken = hasActiveCall && hasHoldingCall;
823        Call.State fgCallState = getActiveFgCallState();
824
825        boolean result = (serviceState != ServiceState.STATE_POWER_OFF
826                && !hasRingingCall
827                && !allLinesTaken
828                && ((fgCallState == Call.State.ACTIVE)
829                    || (fgCallState == Call.State.IDLE)
830                    || (fgCallState == Call.State.DISCONNECTED)));
831
832        if (result == false) {
833            Log.d(LOG_TAG, "canDial serviceState=" + serviceState
834                            + " hasRingingCall=" + hasRingingCall
835                            + " hasActiveCall=" + hasActiveCall
836                            + " hasHoldingCall=" + hasHoldingCall
837                            + " allLinesTaken=" + allLinesTaken
838                            + " fgCallState=" + fgCallState);
839        }
840        return result;
841    }
842
843    /**
844     * Whether or not the phone can do explicit call transfer in the current
845     * phone state--that is, one call holding and one call active.
846     * @return true if the phone can do explicit call transfer; false otherwise.
847     */
848    public boolean canTransfer(Call heldCall) {
849        Phone activePhone = null;
850        Phone heldPhone = null;
851
852        if (hasActiveFgCall()) {
853            activePhone = getActiveFgCall().getPhone();
854        }
855
856        if (heldCall != null) {
857            heldPhone = heldCall.getPhone();
858        }
859
860        return (heldPhone == activePhone && activePhone.canTransfer());
861    }
862
863    /**
864     * Connects the held call and active call
865     * Disconnects the subscriber from both calls
866     *
867     * Explicit Call Transfer occurs asynchronously
868     * and may fail. Final notification occurs via
869     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
870     * java.lang.Object) registerForPreciseCallStateChanged()}.
871     *
872     * @exception CallStateException if canTransfer() would return false.
873     * In these cases, this operation may not be performed.
874     */
875    public void explicitCallTransfer(Call heldCall) throws CallStateException {
876        if (VDBG) {
877            Log.d(LOG_TAG, " explicitCallTransfer(" + heldCall + ")");
878            Log.d(LOG_TAG, this.toString());
879        }
880
881        if (canTransfer(heldCall)) {
882            heldCall.getPhone().explicitCallTransfer();
883        }
884
885        if (VDBG) {
886            Log.d(LOG_TAG, "End explicitCallTransfer(" + heldCall + ")");
887            Log.d(LOG_TAG, this.toString());
888        }
889
890    }
891
892    /**
893     * Returns a list of MMI codes that are pending for a phone. (They have initiated
894     * but have not yet completed).
895     * Presently there is only ever one.
896     *
897     * Use <code>registerForMmiInitiate</code>
898     * and <code>registerForMmiComplete</code> for change notification.
899     * @return null if phone doesn't have or support mmi code
900     */
901    public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
902        Log.e(LOG_TAG, "getPendingMmiCodes not implemented");
903        return null;
904    }
905
906    /**
907     * Sends user response to a USSD REQUEST message.  An MmiCode instance
908     * representing this response is sent to handlers registered with
909     * registerForMmiInitiate.
910     *
911     * @param ussdMessge    Message to send in the response.
912     * @return false if phone doesn't support ussd service
913     */
914    public boolean sendUssdResponse(Phone phone, String ussdMessge) {
915        Log.e(LOG_TAG, "sendUssdResponse not implemented");
916        return false;
917    }
918
919    /**
920     * Mutes or unmutes the microphone for the active call. The microphone
921     * is automatically unmuted if a call is answered, dialed, or resumed
922     * from a holding state.
923     *
924     * @param muted true to mute the microphone,
925     * false to activate the microphone.
926     */
927
928    public void setMute(boolean muted) {
929        if (VDBG) {
930            Log.d(LOG_TAG, " setMute(" + muted + ")");
931            Log.d(LOG_TAG, this.toString());
932        }
933
934        if (hasActiveFgCall()) {
935            getActiveFgCall().getPhone().setMute(muted);
936        }
937
938        if (VDBG) {
939            Log.d(LOG_TAG, "End setMute(" + muted + ")");
940            Log.d(LOG_TAG, this.toString());
941        }
942    }
943
944    /**
945     * Gets current mute status. Use
946     * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
947     * java.lang.Object) registerForPreciseCallStateChanged()}
948     * as a change notifcation, although presently phone state changed is not
949     * fired when setMute() is called.
950     *
951     * @return true is muting, false is unmuting
952     */
953    public boolean getMute() {
954        if (hasActiveFgCall()) {
955            return getActiveFgCall().getPhone().getMute();
956        } else if (hasActiveBgCall()) {
957            return getFirstActiveBgCall().getPhone().getMute();
958        }
959        return false;
960    }
961
962    /**
963     * Enables or disables echo suppression.
964     */
965    public void setEchoSuppressionEnabled(boolean enabled) {
966        if (VDBG) {
967            Log.d(LOG_TAG, " setEchoSuppression(" + enabled + ")");
968            Log.d(LOG_TAG, this.toString());
969        }
970
971        if (hasActiveFgCall()) {
972            getActiveFgCall().getPhone().setEchoSuppressionEnabled(enabled);
973        }
974
975        if (VDBG) {
976            Log.d(LOG_TAG, "End setEchoSuppression(" + enabled + ")");
977            Log.d(LOG_TAG, this.toString());
978        }
979    }
980
981    /**
982     * Play a DTMF tone on the active call.
983     *
984     * @param c should be one of 0-9, '*' or '#'. Other values will be
985     * silently ignored.
986     * @return false if no active call or the active call doesn't support
987     *         dtmf tone
988     */
989    public boolean sendDtmf(char c) {
990        boolean result = false;
991
992        if (VDBG) {
993            Log.d(LOG_TAG, " sendDtmf(" + c + ")");
994            Log.d(LOG_TAG, this.toString());
995        }
996
997        if (hasActiveFgCall()) {
998            getActiveFgCall().getPhone().sendDtmf(c);
999            result = true;
1000        }
1001
1002        if (VDBG) {
1003            Log.d(LOG_TAG, "End sendDtmf(" + c + ")");
1004            Log.d(LOG_TAG, this.toString());
1005        }
1006        return result;
1007    }
1008
1009    /**
1010     * Start to paly a DTMF tone on the active call.
1011     * or there is a playing DTMF tone.
1012     * @param c should be one of 0-9, '*' or '#'. Other values will be
1013     * silently ignored.
1014     *
1015     * @return false if no active call or the active call doesn't support
1016     *         dtmf tone
1017     */
1018    public boolean startDtmf(char c) {
1019        boolean result = false;
1020
1021        if (VDBG) {
1022            Log.d(LOG_TAG, " startDtmf(" + c + ")");
1023            Log.d(LOG_TAG, this.toString());
1024        }
1025
1026        if (hasActiveFgCall()) {
1027            getActiveFgCall().getPhone().startDtmf(c);
1028            result = true;
1029        }
1030
1031        if (VDBG) {
1032            Log.d(LOG_TAG, "End startDtmf(" + c + ")");
1033            Log.d(LOG_TAG, this.toString());
1034        }
1035
1036        return result;
1037    }
1038
1039    /**
1040     * Stop the playing DTMF tone. Ignored if there is no playing DTMF
1041     * tone or no active call.
1042     */
1043    public void stopDtmf() {
1044        if (VDBG) {
1045            Log.d(LOG_TAG, " stopDtmf()" );
1046            Log.d(LOG_TAG, this.toString());
1047        }
1048
1049        if (hasActiveFgCall()) getFgPhone().stopDtmf();
1050
1051        if (VDBG) {
1052            Log.d(LOG_TAG, "End stopDtmf()");
1053            Log.d(LOG_TAG, this.toString());
1054        }
1055    }
1056
1057    /**
1058     * send burst DTMF tone, it can send the string as single character or multiple character
1059     * ignore if there is no active call or not valid digits string.
1060     * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
1061     * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
1062     * this api can send single character and multiple character, also, this api has response
1063     * back to caller.
1064     *
1065     * @param dtmfString is string representing the dialing digit(s) in the active call
1066     * @param on the DTMF ON length in milliseconds, or 0 for default
1067     * @param off the DTMF OFF length in milliseconds, or 0 for default
1068     * @param onComplete is the callback message when the action is processed by BP
1069     *
1070     */
1071    public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1072        if (hasActiveFgCall()) {
1073            getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
1074            return true;
1075        }
1076        return false;
1077    }
1078
1079    /**
1080     * Notifies when a voice connection has disconnected, either due to local
1081     * or remote hangup or error.
1082     *
1083     *  Messages received from this will have the following members:<p>
1084     *  <ul><li>Message.obj will be an AsyncResult</li>
1085     *  <li>AsyncResult.userObj = obj</li>
1086     *  <li>AsyncResult.result = a Connection object that is
1087     *  no longer connected.</li></ul>
1088     */
1089    public void registerForDisconnect(Handler h, int what, Object obj) {
1090        mDisconnectRegistrants.addUnique(h, what, obj);
1091    }
1092
1093    /**
1094     * Unregisters for voice disconnection notification.
1095     * Extraneous calls are tolerated silently
1096     */
1097    public void unregisterForDisconnect(Handler h){
1098        mDisconnectRegistrants.remove(h);
1099    }
1100
1101    /**
1102     * Register for getting notifications for change in the Call State {@link Call.State}
1103     * This is called PreciseCallState because the call state is more precise than the
1104     * {@link Phone.State} which can be obtained using the {@link PhoneStateListener}
1105     *
1106     * Resulting events will have an AsyncResult in <code>Message.obj</code>.
1107     * AsyncResult.userData will be set to the obj argument here.
1108     * The <em>h</em> parameter is held only by a weak reference.
1109     */
1110    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
1111        mPreciseCallStateRegistrants.addUnique(h, what, obj);
1112    }
1113
1114    /**
1115     * Unregisters for voice call state change notifications.
1116     * Extraneous calls are tolerated silently.
1117     */
1118    public void unregisterForPreciseCallStateChanged(Handler h){
1119        mPreciseCallStateRegistrants.remove(h);
1120    }
1121
1122    /**
1123     * Notifies when a previously untracked non-ringing/waiting connection has appeared.
1124     * This is likely due to some other entity (eg, SIM card application) initiating a call.
1125     */
1126    public void registerForUnknownConnection(Handler h, int what, Object obj){
1127        mUnknownConnectionRegistrants.addUnique(h, what, obj);
1128    }
1129
1130    /**
1131     * Unregisters for unknown connection notifications.
1132     */
1133    public void unregisterForUnknownConnection(Handler h){
1134        mUnknownConnectionRegistrants.remove(h);
1135    }
1136
1137
1138    /**
1139     * Notifies when a new ringing or waiting connection has appeared.<p>
1140     *
1141     *  Messages received from this:
1142     *  Message.obj will be an AsyncResult
1143     *  AsyncResult.userObj = obj
1144     *  AsyncResult.result = a Connection. <p>
1145     *  Please check Connection.isRinging() to make sure the Connection
1146     *  has not dropped since this message was posted.
1147     *  If Connection.isRinging() is true, then
1148     *   Connection.getCall() == Phone.getRingingCall()
1149     */
1150    public void registerForNewRingingConnection(Handler h, int what, Object obj){
1151        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
1152    }
1153
1154    /**
1155     * Unregisters for new ringing connection notification.
1156     * Extraneous calls are tolerated silently
1157     */
1158
1159    public void unregisterForNewRingingConnection(Handler h){
1160        mNewRingingConnectionRegistrants.remove(h);
1161    }
1162
1163    /**
1164     * Notifies when an incoming call rings.<p>
1165     *
1166     *  Messages received from this:
1167     *  Message.obj will be an AsyncResult
1168     *  AsyncResult.userObj = obj
1169     *  AsyncResult.result = a Connection. <p>
1170     */
1171    public void registerForIncomingRing(Handler h, int what, Object obj){
1172        mIncomingRingRegistrants.addUnique(h, what, obj);
1173    }
1174
1175    /**
1176     * Unregisters for ring notification.
1177     * Extraneous calls are tolerated silently
1178     */
1179
1180    public void unregisterForIncomingRing(Handler h){
1181        mIncomingRingRegistrants.remove(h);
1182    }
1183
1184    /**
1185     * Notifies when out-band ringback tone is needed.<p>
1186     *
1187     *  Messages received from this:
1188     *  Message.obj will be an AsyncResult
1189     *  AsyncResult.userObj = obj
1190     *  AsyncResult.result = boolean, true to start play ringback tone
1191     *                       and false to stop. <p>
1192     */
1193    public void registerForRingbackTone(Handler h, int what, Object obj){
1194        mRingbackToneRegistrants.addUnique(h, what, obj);
1195    }
1196
1197    /**
1198     * Unregisters for ringback tone notification.
1199     */
1200
1201    public void unregisterForRingbackTone(Handler h){
1202        mRingbackToneRegistrants.remove(h);
1203    }
1204
1205    /**
1206     * Registers the handler to reset the uplink mute state to get
1207     * uplink audio.
1208     */
1209    public void registerForResendIncallMute(Handler h, int what, Object obj){
1210        mResendIncallMuteRegistrants.addUnique(h, what, obj);
1211    }
1212
1213    /**
1214     * Unregisters for resend incall mute notifications.
1215     */
1216    public void unregisterForResendIncallMute(Handler h){
1217        mResendIncallMuteRegistrants.remove(h);
1218    }
1219
1220    /**
1221     * Register for notifications of initiation of a new MMI code request.
1222     * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
1223     *
1224     * Example: If Phone.dial is called with "*#31#", then the app will
1225     * be notified here.<p>
1226     *
1227     * The returned <code>Message.obj</code> will contain an AsyncResult.
1228     *
1229     * <code>obj.result</code> will be an "MmiCode" object.
1230     */
1231    public void registerForMmiInitiate(Handler h, int what, Object obj){
1232        mMmiInitiateRegistrants.addUnique(h, what, obj);
1233    }
1234
1235    /**
1236     * Unregisters for new MMI initiate notification.
1237     * Extraneous calls are tolerated silently
1238     */
1239    public void unregisterForMmiInitiate(Handler h){
1240        mMmiInitiateRegistrants.remove(h);
1241    }
1242
1243    /**
1244     * Register for notifications that an MMI request has completed
1245     * its network activity and is in its final state. This may mean a state
1246     * of COMPLETE, FAILED, or CANCELLED.
1247     *
1248     * <code>Message.obj</code> will contain an AsyncResult.
1249     * <code>obj.result</code> will be an "MmiCode" object
1250     */
1251    public void registerForMmiComplete(Handler h, int what, Object obj){
1252        mMmiCompleteRegistrants.addUnique(h, what, obj);
1253    }
1254
1255    /**
1256     * Unregisters for MMI complete notification.
1257     * Extraneous calls are tolerated silently
1258     */
1259    public void unregisterForMmiComplete(Handler h){
1260        mMmiCompleteRegistrants.remove(h);
1261    }
1262
1263    /**
1264     * Registration point for Ecm timer reset
1265     * @param h handler to notify
1266     * @param what user-defined message code
1267     * @param obj placed in Message.obj
1268     */
1269    public void registerForEcmTimerReset(Handler h, int what, Object obj){
1270        mEcmTimerResetRegistrants.addUnique(h, what, obj);
1271    }
1272
1273    /**
1274     * Unregister for notification for Ecm timer reset
1275     * @param h Handler to be removed from the registrant list.
1276     */
1277    public void unregisterForEcmTimerReset(Handler h){
1278        mEcmTimerResetRegistrants.remove(h);
1279    }
1280
1281    /**
1282     * Register for ServiceState changed.
1283     * Message.obj will contain an AsyncResult.
1284     * AsyncResult.result will be a ServiceState instance
1285     */
1286    public void registerForServiceStateChanged(Handler h, int what, Object obj){
1287        mServiceStateChangedRegistrants.addUnique(h, what, obj);
1288    }
1289
1290    /**
1291     * Unregisters for ServiceStateChange notification.
1292     * Extraneous calls are tolerated silently
1293     */
1294    public void unregisterForServiceStateChanged(Handler h){
1295        mServiceStateChangedRegistrants.remove(h);
1296    }
1297
1298    /**
1299     * Register for notifications when a supplementary service attempt fails.
1300     * Message.obj will contain an AsyncResult.
1301     *
1302     * @param h Handler that receives the notification message.
1303     * @param what User-defined message code.
1304     * @param obj User object.
1305     */
1306    public void registerForSuppServiceFailed(Handler h, int what, Object obj){
1307        mSuppServiceFailedRegistrants.addUnique(h, what, obj);
1308    }
1309
1310    /**
1311     * Unregister for notifications when a supplementary service attempt fails.
1312     * Extraneous calls are tolerated silently
1313     *
1314     * @param h Handler to be removed from the registrant list.
1315     */
1316    public void unregisterForSuppServiceFailed(Handler h){
1317        mSuppServiceFailedRegistrants.remove(h);
1318    }
1319
1320    /**
1321     * Register for notifications when a sInCall VoicePrivacy is enabled
1322     *
1323     * @param h Handler that receives the notification message.
1324     * @param what User-defined message code.
1325     * @param obj User object.
1326     */
1327    public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
1328        mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
1329    }
1330
1331    /**
1332     * Unregister for notifications when a sInCall VoicePrivacy is enabled
1333     *
1334     * @param h Handler to be removed from the registrant list.
1335     */
1336    public void unregisterForInCallVoicePrivacyOn(Handler h){
1337        mInCallVoicePrivacyOnRegistrants.remove(h);
1338    }
1339
1340    /**
1341     * Register for notifications when a sInCall VoicePrivacy is disabled
1342     *
1343     * @param h Handler that receives the notification message.
1344     * @param what User-defined message code.
1345     * @param obj User object.
1346     */
1347    public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
1348        mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
1349    }
1350
1351    /**
1352     * Unregister for notifications when a sInCall VoicePrivacy is disabled
1353     *
1354     * @param h Handler to be removed from the registrant list.
1355     */
1356    public void unregisterForInCallVoicePrivacyOff(Handler h){
1357        mInCallVoicePrivacyOffRegistrants.remove(h);
1358    }
1359
1360    /**
1361     * Register for notifications when CDMA call waiting comes
1362     *
1363     * @param h Handler that receives the notification message.
1364     * @param what User-defined message code.
1365     * @param obj User object.
1366     */
1367    public void registerForCallWaiting(Handler h, int what, Object obj){
1368        mCallWaitingRegistrants.addUnique(h, what, obj);
1369    }
1370
1371    /**
1372     * Unregister for notifications when CDMA Call waiting comes
1373     * @param h Handler to be removed from the registrant list.
1374     */
1375    public void unregisterForCallWaiting(Handler h){
1376        mCallWaitingRegistrants.remove(h);
1377    }
1378
1379
1380    /**
1381     * Register for signal information notifications from the network.
1382     * Message.obj will contain an AsyncResult.
1383     * AsyncResult.result will be a SuppServiceNotification instance.
1384     *
1385     * @param h Handler that receives the notification message.
1386     * @param what User-defined message code.
1387     * @param obj User object.
1388     */
1389
1390    public void registerForSignalInfo(Handler h, int what, Object obj){
1391        mSignalInfoRegistrants.addUnique(h, what, obj);
1392    }
1393
1394    /**
1395     * Unregisters for signal information notifications.
1396     * Extraneous calls are tolerated silently
1397     *
1398     * @param h Handler to be removed from the registrant list.
1399     */
1400    public void unregisterForSignalInfo(Handler h){
1401        mSignalInfoRegistrants.remove(h);
1402    }
1403
1404    /**
1405     * Register for display information notifications from the network.
1406     * Message.obj will contain an AsyncResult.
1407     * AsyncResult.result will be a SuppServiceNotification instance.
1408     *
1409     * @param h Handler that receives the notification message.
1410     * @param what User-defined message code.
1411     * @param obj User object.
1412     */
1413    public void registerForDisplayInfo(Handler h, int what, Object obj){
1414        mDisplayInfoRegistrants.addUnique(h, what, obj);
1415    }
1416
1417    /**
1418     * Unregisters for display information notifications.
1419     * Extraneous calls are tolerated silently
1420     *
1421     * @param h Handler to be removed from the registrant list.
1422     */
1423    public void unregisterForDisplayInfo(Handler h) {
1424        mDisplayInfoRegistrants.remove(h);
1425    }
1426
1427    /**
1428     * Register for notifications when CDMA OTA Provision status change
1429     *
1430     * @param h Handler that receives the notification message.
1431     * @param what User-defined message code.
1432     * @param obj User object.
1433     */
1434    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){
1435        mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
1436    }
1437
1438    /**
1439     * Unregister for notifications when CDMA OTA Provision status change
1440     * @param h Handler to be removed from the registrant list.
1441     */
1442    public void unregisterForCdmaOtaStatusChange(Handler h){
1443        mCdmaOtaStatusChangeRegistrants.remove(h);
1444    }
1445
1446    /**
1447     * Registration point for subscription info ready
1448     * @param h handler to notify
1449     * @param what what code of message when delivered
1450     * @param obj placed in Message.obj
1451     */
1452    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){
1453        mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
1454    }
1455
1456    /**
1457     * Unregister for notifications for subscription info
1458     * @param h Handler to be removed from the registrant list.
1459     */
1460    public void unregisterForSubscriptionInfoReady(Handler h){
1461        mSubscriptionInfoReadyRegistrants.remove(h);
1462    }
1463
1464    /**
1465     * Sets an event to be fired when the telephony system processes
1466     * a post-dial character on an outgoing call.<p>
1467     *
1468     * Messages of type <code>what</code> will be sent to <code>h</code>.
1469     * The <code>obj</code> field of these Message's will be instances of
1470     * <code>AsyncResult</code>. <code>Message.obj.result</code> will be
1471     * a Connection object.<p>
1472     *
1473     * Message.arg1 will be the post dial character being processed,
1474     * or 0 ('\0') if end of string.<p>
1475     *
1476     * If Connection.getPostDialState() == WAIT,
1477     * the application must call
1478     * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
1479     * Connection.proceedAfterWaitChar()} or
1480     * {@link com.android.internal.telephony.Connection#cancelPostDial()
1481     * Connection.cancelPostDial()}
1482     * for the telephony system to continue playing the post-dial
1483     * DTMF sequence.<p>
1484     *
1485     * If Connection.getPostDialState() == WILD,
1486     * the application must call
1487     * {@link com.android.internal.telephony.Connection#proceedAfterWildChar
1488     * Connection.proceedAfterWildChar()}
1489     * or
1490     * {@link com.android.internal.telephony.Connection#cancelPostDial()
1491     * Connection.cancelPostDial()}
1492     * for the telephony system to continue playing the
1493     * post-dial DTMF sequence.<p>
1494     *
1495     */
1496    public void registerForPostDialCharacter(Handler h, int what, Object obj){
1497        mPostDialCharacterRegistrants.addUnique(h, what, obj);
1498    }
1499
1500    public void unregisterForPostDialCharacter(Handler h){
1501        mPostDialCharacterRegistrants.remove(h);
1502    }
1503
1504    /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
1505     * 1. APIs to access list of calls
1506     * 2. APIs to check if any active call, which has connection other than
1507     * disconnected ones, pleaser refer to Call.isIdle()
1508     * 3. APIs to return first active call
1509     * 4. APIs to return the connections of first active call
1510     * 5. APIs to return other property of first active call
1511     */
1512
1513    /**
1514     * @return list of all ringing calls
1515     */
1516    public List<Call> getRingingCalls() {
1517        return Collections.unmodifiableList(mRingingCalls);
1518    }
1519
1520    /**
1521     * @return list of all foreground calls
1522     */
1523    public List<Call> getForegroundCalls() {
1524        return Collections.unmodifiableList(mForegroundCalls);
1525    }
1526
1527    /**
1528     * @return list of all background calls
1529     */
1530    public List<Call> getBackgroundCalls() {
1531        return Collections.unmodifiableList(mBackgroundCalls);
1532    }
1533
1534    /**
1535     * Return true if there is at least one active foreground call
1536     */
1537    public boolean hasActiveFgCall() {
1538        return (getFirstActiveCall(mForegroundCalls) != null);
1539    }
1540
1541    /**
1542     * Return true if there is at least one active background call
1543     */
1544    public boolean hasActiveBgCall() {
1545        // TODO since hasActiveBgCall may get called often
1546        // better to cache it to improve performance
1547        return (getFirstActiveCall(mBackgroundCalls) != null);
1548    }
1549
1550    /**
1551     * Return true if there is at least one active ringing call
1552     *
1553     */
1554    public boolean hasActiveRingingCall() {
1555        return (getFirstActiveCall(mRingingCalls) != null);
1556    }
1557
1558    /**
1559     * return the active foreground call from foreground calls
1560     *
1561     * Active call means the call is NOT in Call.State.IDLE
1562     *
1563     * 1. If there is active foreground call, return it
1564     * 2. If there is no active foreground call, return the
1565     *    foreground call associated with default phone, which state is IDLE.
1566     * 3. If there is no phone registered at all, return null.
1567     *
1568     */
1569    public Call getActiveFgCall() {
1570        Call call = getFirstNonIdleCall(mForegroundCalls);
1571        if (call == null) {
1572            call = (mDefaultPhone == null)
1573                    ? null
1574                    : mDefaultPhone.getForegroundCall();
1575        }
1576        return call;
1577    }
1578
1579    // Returns the first call that is not in IDLE state. If both active calls
1580    // and disconnecting/disconnected calls exist, return the first active call.
1581    private Call getFirstNonIdleCall(List<Call> calls) {
1582        Call result = null;
1583        for (Call call : calls) {
1584            if (!call.isIdle()) {
1585                return call;
1586            } else if (call.getState() != Call.State.IDLE) {
1587                if (result == null) result = call;
1588            }
1589        }
1590        return result;
1591    }
1592
1593    /**
1594     * return one active background call from background calls
1595     *
1596     * Active call means the call is NOT idle defined by Call.isIdle()
1597     *
1598     * 1. If there is only one active background call, return it
1599     * 2. If there is more than one active background call, return the first one
1600     * 3. If there is no active background call, return the background call
1601     *    associated with default phone, which state is IDLE.
1602     * 4. If there is no background call at all, return null.
1603     *
1604     * Complete background calls list can be get by getBackgroundCalls()
1605     */
1606    public Call getFirstActiveBgCall() {
1607        Call call = getFirstNonIdleCall(mBackgroundCalls);
1608        if (call == null) {
1609            call = (mDefaultPhone == null)
1610                    ? null
1611                    : mDefaultPhone.getBackgroundCall();
1612        }
1613        return call;
1614    }
1615
1616    /**
1617     * return one active ringing call from ringing calls
1618     *
1619     * Active call means the call is NOT idle defined by Call.isIdle()
1620     *
1621     * 1. If there is only one active ringing call, return it
1622     * 2. If there is more than one active ringing call, return the first one
1623     * 3. If there is no active ringing call, return the ringing call
1624     *    associated with default phone, which state is IDLE.
1625     * 4. If there is no ringing call at all, return null.
1626     *
1627     * Complete ringing calls list can be get by getRingingCalls()
1628     */
1629    public Call getFirstActiveRingingCall() {
1630        Call call = getFirstNonIdleCall(mRingingCalls);
1631        if (call == null) {
1632            call = (mDefaultPhone == null)
1633                    ? null
1634                    : mDefaultPhone.getRingingCall();
1635        }
1636        return call;
1637    }
1638
1639    /**
1640     * @return the state of active foreground call
1641     * return IDLE if there is no active foreground call
1642     */
1643    public Call.State getActiveFgCallState() {
1644        Call fgCall = getActiveFgCall();
1645
1646        if (fgCall != null) {
1647            return fgCall.getState();
1648        }
1649
1650        return Call.State.IDLE;
1651    }
1652
1653    /**
1654     * @return the connections of active foreground call
1655     * return empty list if there is no active foreground call
1656     */
1657    public List<Connection> getFgCallConnections() {
1658        Call fgCall = getActiveFgCall();
1659        if ( fgCall != null) {
1660            return fgCall.getConnections();
1661        }
1662        return emptyConnections;
1663    }
1664
1665    /**
1666     * @return the connections of active background call
1667     * return empty list if there is no active background call
1668     */
1669    public List<Connection> getBgCallConnections() {
1670        Call bgCall = getFirstActiveBgCall();
1671        if ( bgCall != null) {
1672            return bgCall.getConnections();
1673        }
1674        return emptyConnections;
1675    }
1676
1677    /**
1678     * @return the latest connection of active foreground call
1679     * return null if there is no active foreground call
1680     */
1681    public Connection getFgCallLatestConnection() {
1682        Call fgCall = getActiveFgCall();
1683        if ( fgCall != null) {
1684            return fgCall.getLatestConnection();
1685        }
1686        return null;
1687    }
1688
1689    /**
1690     * @return true if there is at least one Foreground call in disconnected state
1691     */
1692    public boolean hasDisconnectedFgCall() {
1693        return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
1694    }
1695
1696    /**
1697     * @return true if there is at least one background call in disconnected state
1698     */
1699    public boolean hasDisconnectedBgCall() {
1700        return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
1701    }
1702
1703    /**
1704     * @return the first active call from a call list
1705     */
1706    private  Call getFirstActiveCall(ArrayList<Call> calls) {
1707        for (Call call : calls) {
1708            if (!call.isIdle()) {
1709                return call;
1710            }
1711        }
1712        return null;
1713    }
1714
1715    /**
1716     * @return the first call in a the Call.state from a call list
1717     */
1718    private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
1719        for (Call call : calls) {
1720            if (call.getState() == state) {
1721                return call;
1722            }
1723        }
1724        return null;
1725    }
1726
1727
1728    private boolean hasMoreThanOneRingingCall() {
1729        int count = 0;
1730        for (Call call : mRingingCalls) {
1731            if (call.getState().isRinging()) {
1732                if (++count > 1) return true;
1733            }
1734        }
1735        return false;
1736    }
1737
1738    private Handler mHandler = new Handler() {
1739
1740        @Override
1741        public void handleMessage(Message msg) {
1742
1743            switch (msg.what) {
1744                case EVENT_DISCONNECT:
1745                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISCONNECT)");
1746                    mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1747                    break;
1748                case EVENT_PRECISE_CALL_STATE_CHANGED:
1749                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)");
1750                    mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1751                    break;
1752                case EVENT_NEW_RINGING_CONNECTION:
1753                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_NEW_RINGING_CONNECTION)");
1754                    if (getActiveFgCallState().isDialing() || hasMoreThanOneRingingCall()) {
1755                        Connection c = (Connection) ((AsyncResult) msg.obj).result;
1756                        try {
1757                            Log.d(LOG_TAG, "silently drop incoming call: " + c.getCall());
1758                            c.getCall().hangup();
1759                        } catch (CallStateException e) {
1760                            Log.w(LOG_TAG, "new ringing connection", e);
1761                        }
1762                    } else {
1763                        mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1764                    }
1765                    break;
1766                case EVENT_UNKNOWN_CONNECTION:
1767                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_UNKNOWN_CONNECTION)");
1768                    mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1769                    break;
1770                case EVENT_INCOMING_RING:
1771                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_INCOMING_RING)");
1772                    // The event may come from RIL who's not aware of an ongoing fg call
1773                    if (!hasActiveFgCall()) {
1774                        mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1775                    }
1776                    break;
1777                case EVENT_RINGBACK_TONE:
1778                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RINGBACK_TONE)");
1779                    mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1780                    break;
1781                case EVENT_IN_CALL_VOICE_PRIVACY_ON:
1782                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_ON)");
1783                    mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1784                    break;
1785                case EVENT_IN_CALL_VOICE_PRIVACY_OFF:
1786                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_IN_CALL_VOICE_PRIVACY_OFF)");
1787                    mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1788                    break;
1789                case EVENT_CALL_WAITING:
1790                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CALL_WAITING)");
1791                    mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1792                    break;
1793                case EVENT_DISPLAY_INFO:
1794                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_DISPLAY_INFO)");
1795                    mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1796                    break;
1797                case EVENT_SIGNAL_INFO:
1798                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SIGNAL_INFO)");
1799                    mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1800                    break;
1801                case EVENT_CDMA_OTA_STATUS_CHANGE:
1802                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_CDMA_OTA_STATUS_CHANGE)");
1803                    mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1804                    break;
1805                case EVENT_RESEND_INCALL_MUTE:
1806                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_RESEND_INCALL_MUTE)");
1807                    mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1808                    break;
1809                case EVENT_MMI_INITIATE:
1810                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_INITIATE)");
1811                    mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1812                    break;
1813                case EVENT_MMI_COMPLETE:
1814                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
1815                    mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1816                    break;
1817                case EVENT_ECM_TIMER_RESET:
1818                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_ECM_TIMER_RESET)");
1819                    mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1820                    break;
1821                case EVENT_SUBSCRIPTION_INFO_READY:
1822                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUBSCRIPTION_INFO_READY)");
1823                    mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1824                    break;
1825                case EVENT_SUPP_SERVICE_FAILED:
1826                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SUPP_SERVICE_FAILED)");
1827                    mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1828                    break;
1829                case EVENT_SERVICE_STATE_CHANGED:
1830                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_SERVICE_STATE_CHANGED)");
1831                    mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
1832                    break;
1833                case EVENT_POST_DIAL_CHARACTER:
1834                    // we need send the character that is being processed in msg.arg1
1835                    // so can't use notifyRegistrants()
1836                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_POST_DIAL_CHARACTER)");
1837                    for(int i=0; i < mPostDialCharacterRegistrants.size(); i++) {
1838                        Message notifyMsg;
1839                        notifyMsg = ((Registrant)mPostDialCharacterRegistrants.get(i)).messageForRegistrant();
1840                        notifyMsg.obj = msg.obj;
1841                        notifyMsg.arg1 = msg.arg1;
1842                        notifyMsg.sendToTarget();
1843                    }
1844                    break;
1845            }
1846        }
1847    };
1848
1849    @Override
1850    public String toString() {
1851        Call call;
1852        StringBuilder b = new StringBuilder();
1853
1854        b.append("CallManager {");
1855        b.append("\nstate = " + getState());
1856        call = getActiveFgCall();
1857        b.append("\n- Foreground: " + getActiveFgCallState());
1858        b.append(" from " + call.getPhone());
1859        b.append("\n  Conn: ").append(getFgCallConnections());
1860        call = getFirstActiveBgCall();
1861        b.append("\n- Background: " + call.getState());
1862        b.append(" from " + call.getPhone());
1863        b.append("\n  Conn: ").append(getBgCallConnections());
1864        call = getFirstActiveRingingCall();
1865        b.append("\n- Ringing: " +call.getState());
1866        b.append(" from " + call.getPhone());
1867
1868        for (Phone phone : getAllPhones()) {
1869            if (phone != null) {
1870                b.append("\nPhone: " + phone + ", name = " + phone.getPhoneName()
1871                        + ", state = " + phone.getState());
1872                call = phone.getForegroundCall();
1873                b.append("\n- Foreground: ").append(call);
1874                call = phone.getBackgroundCall();
1875                b.append(" Background: ").append(call);
1876                call = phone.getRingingCall();
1877                b.append(" Ringing: ").append(call);
1878            }
1879        }
1880        b.append("\n}");
1881        return b.toString();
1882    }
1883}
1884