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