1 /*
2  * Copyright (C) 2006 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.gsm;
18 
19 import android.content.ContentValues;
20 import android.content.Context;
21 import android.content.SharedPreferences;
22 import android.database.SQLException;
23 import android.net.Uri;
24 import android.os.AsyncResult;
25 import android.os.Bundle;
26 import android.os.Handler;
27 import android.os.Message;
28 import android.os.Registrant;
29 import android.os.RegistrantList;
30 import android.preference.PreferenceManager;
31 import android.provider.Telephony;
32 import android.telecom.VideoProfile;
33 import android.telephony.CellLocation;
34 import android.telephony.PhoneNumberUtils;
35 import android.telephony.ServiceState;
36 import android.telephony.SubscriptionManager;
37 import android.telephony.TelephonyManager;
38 
39 import com.android.internal.telephony.CallTracker;
40 
41 import android.text.TextUtils;
42 import android.telephony.Rlog;
43 import android.util.Log;
44 
45 import com.android.ims.ImsManager;
46 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
47 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
48 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
49 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
50 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
51 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
52 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
53 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
54 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
55 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
56 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
57 
58 import com.android.internal.telephony.dataconnection.DcTracker;
59 import com.android.internal.telephony.Call;
60 import com.android.internal.telephony.CallForwardInfo;
61 import com.android.internal.telephony.CallStateException;
62 import com.android.internal.telephony.CommandsInterface;
63 import com.android.internal.telephony.Connection;
64 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
65 import com.android.internal.telephony.MmiCode;
66 import com.android.internal.telephony.Phone;
67 import com.android.internal.telephony.PhoneBase;
68 import com.android.internal.telephony.PhoneConstants;
69 import com.android.internal.telephony.PhoneNotifier;
70 import com.android.internal.telephony.PhoneProxy;
71 import com.android.internal.telephony.PhoneSubInfo;
72 import com.android.internal.telephony.UUSInfo;
73 import com.android.internal.telephony.imsphone.ImsPhone;
74 import com.android.internal.telephony.test.SimulatedRadioControl;
75 import com.android.internal.telephony.uicc.IccRecords;
76 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
77 import com.android.internal.telephony.uicc.UiccCard;
78 import com.android.internal.telephony.uicc.UiccCardApplication;
79 import com.android.internal.telephony.uicc.UiccController;
80 import com.android.internal.telephony.ServiceStateTracker;
81 import com.android.internal.telephony.uicc.IsimRecords;
82 import com.android.internal.telephony.uicc.IsimUiccRecords;
83 
84 import java.io.FileDescriptor;
85 import java.io.PrintWriter;
86 import java.util.ArrayList;
87 import java.util.List;
88 
89 
90 /**
91  * {@hide}
92  */
93 public class GSMPhone extends PhoneBase {
94     // NOTE that LOG_TAG here is "GSM", which means that log messages
95     // from this file will go into the radio log rather than the main
96     // log.  (Use "adb logcat -b radio" to see them.)
97     static final String LOG_TAG = "GSMPhone";
98     private static final boolean LOCAL_DEBUG = true;
99     private static final boolean VDBG = false; /* STOPSHIP if true */
100 
101     // Key used to read/write current ciphering state
102     public static final String CIPHERING_KEY = "ciphering_key";
103     // Key used to read/write voice mail number
104     public static final String VM_NUMBER = "vm_number_key";
105     // Key used to read/write the SIM IMSI used for storing the voice mail
106     public static final String VM_SIM_IMSI = "vm_sim_imsi_key";
107 
108     // Instance Variables
109     GsmCallTracker mCT;
110     GsmServiceStateTracker mSST;
111     ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>();
112     SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
113     PhoneSubInfo mSubInfo;
114 
115 
116     Registrant mPostDialHandler;
117 
118     /** List of Registrants to receive Supplementary Service Notifications. */
119     RegistrantList mSsnRegistrants = new RegistrantList();
120 
121     // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
122     private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
123 
124     private String mImei;
125     private String mImeiSv;
126     private String mVmNumber;
127 
128     private IsimUiccRecords mIsimUiccRecords;
129 
130     // Create Cfu (Call forward unconditional) so that dialing number &
131     // mOnComplete (Message object passed by client) can be packed &
132     // given as a single Cfu object as user data to RIL.
133     private static class Cfu {
134         final String mSetCfNumber;
135         final Message mOnComplete;
136 
Cfu(String cfNumber, Message onComplete)137         Cfu(String cfNumber, Message onComplete) {
138             mSetCfNumber = cfNumber;
139             mOnComplete = onComplete;
140         }
141     }
142 
143     // Constructors
144 
145     public
GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode)146     GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
147         super("GSM", notifier, context, ci, unitTestMode);
148 
149         if (ci instanceof SimulatedRadioControl) {
150             mSimulatedRadioControl = (SimulatedRadioControl) ci;
151         }
152 
153         mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
154         mCT = new GsmCallTracker(this);
155 
156         mSST = new GsmServiceStateTracker(this);
157         mDcTracker = new DcTracker(this);
158 
159         if (!unitTestMode) {
160             mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
161             mSubInfo = new PhoneSubInfo(this);
162         }
163 
164         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
165         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
166         mCi.registerForOn(this, EVENT_RADIO_ON, null);
167         mCi.setOnUSSD(this, EVENT_USSD, null);
168         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
169         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
170         mCi.setOnSs(this, EVENT_SS, null);
171         setProperties();
172     }
173 
174     public
GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId)175     GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId) {
176         this(context, ci, notifier, false, phoneId);
177     }
178 
179     public
GSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId)180     GSMPhone(Context context, CommandsInterface ci,
181             PhoneNotifier notifier, boolean unitTestMode, int phoneId) {
182         super("GSM", notifier, context, ci, unitTestMode, phoneId);
183 
184         if (ci instanceof SimulatedRadioControl) {
185             mSimulatedRadioControl = (SimulatedRadioControl) ci;
186         }
187 
188         mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
189         mCT = new GsmCallTracker(this);
190 
191         mSST = new GsmServiceStateTracker(this);
192         mDcTracker = new DcTracker(this);
193 
194         if (!unitTestMode) {
195             mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
196             mSubInfo = new PhoneSubInfo(this);
197         }
198 
199         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
200         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
201         mCi.registerForOn(this, EVENT_RADIO_ON, null);
202         mCi.setOnUSSD(this, EVENT_USSD, null);
203         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
204         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
205         mCi.setOnSs(this, EVENT_SS, null);
206         setProperties();
207 
208         log("GSMPhone: constructor: sub = " + mPhoneId);
209 
210         setProperties();
211     }
212 
setProperties()213     protected void setProperties() {
214         TelephonyManager.from(mContext).setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
215     }
216 
217     @Override
dispose()218     public void dispose() {
219         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
220             super.dispose();
221 
222             //Unregister from all former registered events
223             mCi.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
224             unregisterForSimRecordEvents();
225             mCi.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
226             mCi.unregisterForOn(this); //EVENT_RADIO_ON
227             mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK
228             mCi.unSetOnUSSD(this);
229             mCi.unSetOnSuppServiceNotification(this);
230             mCi.unSetOnSs(this);
231 
232             mPendingMMIs.clear();
233 
234             //Force all referenced classes to unregister their former registered events
235             mCT.dispose();
236             mDcTracker.dispose();
237             mSST.dispose();
238             mSimPhoneBookIntManager.dispose();
239             mSubInfo.dispose();
240         }
241     }
242 
243     @Override
removeReferences()244     public void removeReferences() {
245         Rlog.d(LOG_TAG, "removeReferences");
246         mSimulatedRadioControl = null;
247         mSimPhoneBookIntManager = null;
248         mSubInfo = null;
249         mCT = null;
250         mSST = null;
251 
252         super.removeReferences();
253     }
254 
255     @Override
finalize()256     protected void finalize() {
257         if(LOCAL_DEBUG) Rlog.d(LOG_TAG, "GSMPhone finalized");
258     }
259 
260     @Override
261     public ServiceState
getServiceState()262     getServiceState() {
263         if (mSST == null || mSST.mSS.getState() != ServiceState.STATE_IN_SERVICE) {
264             if (mImsPhone != null) {
265                 return ServiceState.mergeServiceStates(
266                         (mSST == null) ? new ServiceState() : mSST.mSS,
267                         mImsPhone.getServiceState());
268             }
269         }
270 
271         if (mSST != null) {
272             return mSST.mSS;
273         } else {
274             // avoid potential NPE in EmergencyCallHelper during Phone switch
275             return new ServiceState();
276         }
277     }
278 
279     @Override
getCellLocation()280     public CellLocation getCellLocation() {
281         return mSST.getCellLocation();
282     }
283 
284     @Override
getState()285     public PhoneConstants.State getState() {
286         if (mImsPhone != null) {
287             PhoneConstants.State imsState = mImsPhone.getState();
288             if (imsState != PhoneConstants.State.IDLE) {
289                 return imsState;
290             }
291         }
292 
293         return mCT.mState;
294     }
295 
296     @Override
getPhoneType()297     public int getPhoneType() {
298         return PhoneConstants.PHONE_TYPE_GSM;
299     }
300 
301     @Override
getServiceStateTracker()302     public ServiceStateTracker getServiceStateTracker() {
303         return mSST;
304     }
305 
306     @Override
getCallTracker()307     public CallTracker getCallTracker() {
308         return mCT;
309     }
310 
311     // pending voice mail count updated after phone creation
updateVoiceMail()312     private void updateVoiceMail() {
313         int countVoiceMessages = 0;
314         IccRecords r = mIccRecords.get();
315         if (r != null) {
316             // get voice mail count from SIM
317             countVoiceMessages = r.getVoiceMessageCount();
318         }
319         int countVoiceMessagesStored = getStoredVoiceMessageCount();
320         if (countVoiceMessages == -1 && countVoiceMessagesStored != 0) {
321             countVoiceMessages = countVoiceMessagesStored;
322         }
323         Rlog.d(LOG_TAG, "updateVoiceMail countVoiceMessages = " + countVoiceMessages
324                 +" subId "+getSubId());
325         setVoiceMessageCount(countVoiceMessages);
326     }
327 
328     @Override
329     public List<? extends MmiCode>
getPendingMmiCodes()330     getPendingMmiCodes() {
331         return mPendingMMIs;
332     }
333 
334     @Override
getDataConnectionState(String apnType)335     public PhoneConstants.DataState getDataConnectionState(String apnType) {
336         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
337 
338         if (mSST == null) {
339             // Radio Technology Change is ongoning, dispose() and removeReferences() have
340             // already been called
341 
342             ret = PhoneConstants.DataState.DISCONNECTED;
343         } else if (!apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY) &&
344                 mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
345             // If we're out of service, open TCP sockets may still work
346             // but no data will flow
347 
348             // Emergency APN is available even in Out Of Service
349             // Pass the actual State of EPDN
350 
351             ret = PhoneConstants.DataState.DISCONNECTED;
352         } else if (mDcTracker.isApnTypeEnabled(apnType) == false ||
353                 mDcTracker.isApnTypeActive(apnType) == false) {
354             //TODO: isApnTypeActive() is just checking whether ApnContext holds
355             //      Dataconnection or not. Checking each ApnState below should
356             //      provide the same state. Calling isApnTypeActive() can be removed.
357             ret = PhoneConstants.DataState.DISCONNECTED;
358         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
359             switch (mDcTracker.getState(apnType)) {
360                 case RETRYING:
361                 case FAILED:
362                 case IDLE:
363                     ret = PhoneConstants.DataState.DISCONNECTED;
364                 break;
365 
366                 case CONNECTED:
367                 case DISCONNECTING:
368                     if ( mCT.mState != PhoneConstants.State.IDLE
369                             && !mSST.isConcurrentVoiceAndDataAllowed()) {
370                         ret = PhoneConstants.DataState.SUSPENDED;
371                     } else {
372                         ret = PhoneConstants.DataState.CONNECTED;
373                     }
374                 break;
375 
376                 case CONNECTING:
377                 case SCANNING:
378                     ret = PhoneConstants.DataState.CONNECTING;
379                 break;
380             }
381         }
382 
383         return ret;
384     }
385 
386     @Override
getDataActivityState()387     public DataActivityState getDataActivityState() {
388         DataActivityState ret = DataActivityState.NONE;
389 
390         if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
391             switch (mDcTracker.getActivity()) {
392                 case DATAIN:
393                     ret = DataActivityState.DATAIN;
394                 break;
395 
396                 case DATAOUT:
397                     ret = DataActivityState.DATAOUT;
398                 break;
399 
400                 case DATAINANDOUT:
401                     ret = DataActivityState.DATAINANDOUT;
402                 break;
403 
404                 case DORMANT:
405                     ret = DataActivityState.DORMANT;
406                 break;
407 
408                 default:
409                     ret = DataActivityState.NONE;
410                 break;
411             }
412         }
413 
414         return ret;
415     }
416 
417     /**
418      * Notify any interested party of a Phone state change
419      * {@link com.android.internal.telephony.PhoneConstants.State}
420      */
notifyPhoneStateChanged()421     /*package*/ void notifyPhoneStateChanged() {
422         mNotifier.notifyPhoneState(this);
423     }
424 
425     /**
426      * Notify registrants of a change in the call state. This notifies changes in
427      * {@link com.android.internal.telephony.Call.State}. Use this when changes
428      * in the precise call state are needed, else use notifyPhoneStateChanged.
429      */
notifyPreciseCallStateChanged()430     /*package*/ void notifyPreciseCallStateChanged() {
431         /* we'd love it if this was package-scoped*/
432         super.notifyPreciseCallStateChangedP();
433     }
434 
notifyNewRingingConnection(Connection c)435     public void notifyNewRingingConnection(Connection c) {
436         super.notifyNewRingingConnectionP(c);
437     }
438 
439     /*package*/ void
notifyDisconnect(Connection cn)440     notifyDisconnect(Connection cn) {
441         mDisconnectRegistrants.notifyResult(cn);
442 
443         mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause());
444     }
445 
notifyUnknownConnection(Connection cn)446     void notifyUnknownConnection(Connection cn) {
447         mUnknownConnectionRegistrants.notifyResult(cn);
448     }
449 
notifySuppServiceFailed(SuppService code)450     void notifySuppServiceFailed(SuppService code) {
451         mSuppServiceFailedRegistrants.notifyResult(code);
452     }
453 
454     /*package*/ void
notifyServiceStateChanged(ServiceState ss)455     notifyServiceStateChanged(ServiceState ss) {
456         super.notifyServiceStateChangedP(ss);
457     }
458 
459     /*package*/
notifyLocationChanged()460     void notifyLocationChanged() {
461         mNotifier.notifyCellLocation(this);
462     }
463 
464     @Override
465     public void
notifyCallForwardingIndicator()466     notifyCallForwardingIndicator() {
467         mNotifier.notifyCallForwardingChanged(this);
468     }
469 
470     // override for allowing access from other classes of this package
471     /**
472      * {@inheritDoc}
473      */
474     @Override
475     public void
setSystemProperty(String property, String value)476     setSystemProperty(String property, String value) {
477         TelephonyManager.setTelephonyProperty(mPhoneId, property, value);
478     }
479 
480     @Override
registerForSuppServiceNotification( Handler h, int what, Object obj)481     public void registerForSuppServiceNotification(
482             Handler h, int what, Object obj) {
483         mSsnRegistrants.addUnique(h, what, obj);
484         if (mSsnRegistrants.size() == 1) mCi.setSuppServiceNotifications(true, null);
485     }
486 
487     @Override
unregisterForSuppServiceNotification(Handler h)488     public void unregisterForSuppServiceNotification(Handler h) {
489         mSsnRegistrants.remove(h);
490         if (mSsnRegistrants.size() == 0) mCi.setSuppServiceNotifications(false, null);
491     }
492 
493     @Override
registerForSimRecordsLoaded(Handler h, int what, Object obj)494     public void registerForSimRecordsLoaded(Handler h, int what, Object obj) {
495         mSimRecordsLoadedRegistrants.addUnique(h, what, obj);
496     }
497 
498     @Override
unregisterForSimRecordsLoaded(Handler h)499     public void unregisterForSimRecordsLoaded(Handler h) {
500         mSimRecordsLoadedRegistrants.remove(h);
501     }
502 
503     @Override
504     public void
acceptCall(int videoState)505     acceptCall(int videoState) throws CallStateException {
506         ImsPhone imsPhone = mImsPhone;
507         if ( imsPhone != null && imsPhone.getRingingCall().isRinging() ) {
508             imsPhone.acceptCall(videoState);
509         } else {
510             mCT.acceptCall();
511         }
512     }
513 
514     @Override
515     public void
rejectCall()516     rejectCall() throws CallStateException {
517         mCT.rejectCall();
518     }
519 
520     @Override
521     public void
switchHoldingAndActive()522     switchHoldingAndActive() throws CallStateException {
523         mCT.switchWaitingOrHoldingAndActive();
524     }
525 
526     @Override
canConference()527     public boolean canConference() {
528         boolean canImsConference = false;
529         if (mImsPhone != null) {
530             canImsConference = mImsPhone.canConference();
531         }
532         return mCT.canConference() || canImsConference;
533     }
534 
canDial()535     public boolean canDial() {
536         return mCT.canDial();
537     }
538 
539     @Override
conference()540     public void conference() {
541         if (mImsPhone != null && mImsPhone.canConference()) {
542             log("conference() - delegated to IMS phone");
543             mImsPhone.conference();
544             return;
545         }
546         mCT.conference();
547     }
548 
549     @Override
clearDisconnected()550     public void clearDisconnected() {
551         mCT.clearDisconnected();
552     }
553 
554     @Override
canTransfer()555     public boolean canTransfer() {
556         return mCT.canTransfer();
557     }
558 
559     @Override
explicitCallTransfer()560     public void explicitCallTransfer() {
561         mCT.explicitCallTransfer();
562     }
563 
564     @Override
565     public GsmCall
getForegroundCall()566     getForegroundCall() {
567         return mCT.mForegroundCall;
568     }
569 
570     @Override
571     public GsmCall
getBackgroundCall()572     getBackgroundCall() {
573         return mCT.mBackgroundCall;
574     }
575 
576     @Override
getRingingCall()577     public Call getRingingCall() {
578         ImsPhone imsPhone = mImsPhone;
579         if ( mCT.mRingingCall != null && mCT.mRingingCall.isRinging() ) {
580             return mCT.mRingingCall;
581         } else if ( imsPhone != null ) {
582             return imsPhone.getRingingCall();
583         }
584         return mCT.mRingingCall;
585     }
586 
handleCallDeflectionIncallSupplementaryService( String dialString)587     private boolean handleCallDeflectionIncallSupplementaryService(
588             String dialString) {
589         if (dialString.length() > 1) {
590             return false;
591         }
592 
593         if (getRingingCall().getState() != GsmCall.State.IDLE) {
594             if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 0: rejectCall");
595             try {
596                 mCT.rejectCall();
597             } catch (CallStateException e) {
598                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
599                     "reject failed", e);
600                 notifySuppServiceFailed(Phone.SuppService.REJECT);
601             }
602         } else if (getBackgroundCall().getState() != GsmCall.State.IDLE) {
603             if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
604                     "MmiCode 0: hangupWaitingOrBackground");
605             mCT.hangupWaitingOrBackground();
606         }
607 
608         return true;
609     }
610 
handleCallWaitingIncallSupplementaryService( String dialString)611     private boolean handleCallWaitingIncallSupplementaryService(
612             String dialString) {
613         int len = dialString.length();
614 
615         if (len > 2) {
616             return false;
617         }
618 
619         GsmCall call = getForegroundCall();
620 
621         try {
622             if (len > 1) {
623                 char ch = dialString.charAt(1);
624                 int callIndex = ch - '0';
625 
626                 if (callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) {
627                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
628                             "MmiCode 1: hangupConnectionByIndex " +
629                             callIndex);
630                     mCT.hangupConnectionByIndex(call, callIndex);
631                 }
632             } else {
633                 if (call.getState() != GsmCall.State.IDLE) {
634                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
635                             "MmiCode 1: hangup foreground");
636                     //mCT.hangupForegroundResumeBackground();
637                     mCT.hangup(call);
638                 } else {
639                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
640                             "MmiCode 1: switchWaitingOrHoldingAndActive");
641                     mCT.switchWaitingOrHoldingAndActive();
642                 }
643             }
644         } catch (CallStateException e) {
645             if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
646                 "hangup failed", e);
647             notifySuppServiceFailed(Phone.SuppService.HANGUP);
648         }
649 
650         return true;
651     }
652 
handleCallHoldIncallSupplementaryService(String dialString)653     private boolean handleCallHoldIncallSupplementaryService(String dialString) {
654         int len = dialString.length();
655 
656         if (len > 2) {
657             return false;
658         }
659 
660         GsmCall call = getForegroundCall();
661 
662         if (len > 1) {
663             try {
664                 char ch = dialString.charAt(1);
665                 int callIndex = ch - '0';
666                 GsmConnection conn = mCT.getConnectionByIndex(call, callIndex);
667 
668                 // gsm index starts at 1, up to 5 connections in a call,
669                 if (conn != null && callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) {
670                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 2: separate call "+
671                             callIndex);
672                     mCT.separate(conn);
673                 } else {
674                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "separate: invalid call index "+
675                             callIndex);
676                     notifySuppServiceFailed(Phone.SuppService.SEPARATE);
677                 }
678             } catch (CallStateException e) {
679                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
680                     "separate failed", e);
681                 notifySuppServiceFailed(Phone.SuppService.SEPARATE);
682             }
683         } else {
684             try {
685                 if (getRingingCall().getState() != GsmCall.State.IDLE) {
686                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
687                     "MmiCode 2: accept ringing call");
688                     mCT.acceptCall();
689                 } else {
690                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
691                     "MmiCode 2: switchWaitingOrHoldingAndActive");
692                     mCT.switchWaitingOrHoldingAndActive();
693                 }
694             } catch (CallStateException e) {
695                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
696                     "switch failed", e);
697                 notifySuppServiceFailed(Phone.SuppService.SWITCH);
698             }
699         }
700 
701         return true;
702     }
703 
handleMultipartyIncallSupplementaryService( String dialString)704     private boolean handleMultipartyIncallSupplementaryService(
705             String dialString) {
706         if (dialString.length() > 1) {
707             return false;
708         }
709 
710         if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 3: merge calls");
711         conference();
712         return true;
713     }
714 
handleEctIncallSupplementaryService(String dialString)715     private boolean handleEctIncallSupplementaryService(String dialString) {
716 
717         int len = dialString.length();
718 
719         if (len != 1) {
720             return false;
721         }
722 
723         if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 4: explicit call transfer");
724         explicitCallTransfer();
725         return true;
726     }
727 
handleCcbsIncallSupplementaryService(String dialString)728     private boolean handleCcbsIncallSupplementaryService(String dialString) {
729         if (dialString.length() > 1) {
730             return false;
731         }
732 
733         Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!");
734         // Treat it as an "unknown" service.
735         notifySuppServiceFailed(Phone.SuppService.UNKNOWN);
736         return true;
737     }
738 
739     @Override
handleInCallMmiCommands(String dialString)740     public boolean handleInCallMmiCommands(String dialString) throws CallStateException {
741         ImsPhone imsPhone = mImsPhone;
742         if (imsPhone != null
743                 && imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
744             return imsPhone.handleInCallMmiCommands(dialString);
745         }
746 
747         if (!isInCall()) {
748             return false;
749         }
750 
751         if (TextUtils.isEmpty(dialString)) {
752             return false;
753         }
754 
755         boolean result = false;
756         char ch = dialString.charAt(0);
757         switch (ch) {
758             case '0':
759                 result = handleCallDeflectionIncallSupplementaryService(
760                         dialString);
761                 break;
762             case '1':
763                 result = handleCallWaitingIncallSupplementaryService(
764                         dialString);
765                 break;
766             case '2':
767                 result = handleCallHoldIncallSupplementaryService(dialString);
768                 break;
769             case '3':
770                 result = handleMultipartyIncallSupplementaryService(dialString);
771                 break;
772             case '4':
773                 result = handleEctIncallSupplementaryService(dialString);
774                 break;
775             case '5':
776                 result = handleCcbsIncallSupplementaryService(dialString);
777                 break;
778             default:
779                 break;
780         }
781 
782         return result;
783     }
784 
isInCall()785     boolean isInCall() {
786         GsmCall.State foregroundCallState = getForegroundCall().getState();
787         GsmCall.State backgroundCallState = getBackgroundCall().getState();
788         GsmCall.State ringingCallState = getRingingCall().getState();
789 
790        return (foregroundCallState.isAlive() ||
791                 backgroundCallState.isAlive() ||
792                 ringingCallState.isAlive());
793     }
794 
795     @Override
796     public Connection
dial(String dialString, int videoState)797     dial(String dialString, int videoState) throws CallStateException {
798         return dial(dialString, null, videoState, null);
799     }
800 
801     @Override
802     public Connection
dial(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)803     dial (String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
804             throws CallStateException {
805         boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);
806         ImsPhone imsPhone = mImsPhone;
807 
808         boolean imsUseEnabled = isImsUseEnabled()
809                  && imsPhone != null
810                  && (imsPhone.isVolteEnabled() || imsPhone.isVowifiEnabled())
811                  && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE);
812 
813         boolean useImsForEmergency = ImsManager.isVolteEnabledByPlatform(mContext)
814                 && imsPhone != null
815                 && isEmergency
816                 &&  mContext.getResources().getBoolean(
817                         com.android.internal.R.bool.useImsAlwaysForEmergencyCall)
818                 && ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext)
819                 && (imsPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF);
820 
821         if (LOCAL_DEBUG) {
822             Rlog.d(LOG_TAG, "imsUseEnabled=" + imsUseEnabled
823                     + ", useImsForEmergency=" + useImsForEmergency
824                     + ", imsPhone=" + imsPhone
825                     + ", imsPhone.isVolteEnabled()="
826                     + ((imsPhone != null) ? imsPhone.isVolteEnabled() : "N/A")
827                     + ", imsPhone.isVowifiEnabled()="
828                     + ((imsPhone != null) ? imsPhone.isVowifiEnabled() : "N/A")
829                     + ", imsPhone.getServiceState().getState()="
830                     + ((imsPhone != null) ? imsPhone.getServiceState().getState() : "N/A"));
831         }
832 
833         ImsPhone.checkWfcWifiOnlyModeBeforeDial(mImsPhone, mContext);
834 
835         if (imsUseEnabled || useImsForEmergency) {
836             try {
837                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Trying IMS PS call");
838                 return imsPhone.dial(dialString, uusInfo, videoState, intentExtras);
839             } catch (CallStateException e) {
840                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "IMS PS call exception " + e +
841                         "imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone);
842                 if (!ImsPhone.CS_FALLBACK.equals(e.getMessage())) {
843                     CallStateException ce = new CallStateException(e.getMessage());
844                     ce.setStackTrace(e.getStackTrace());
845                     throw ce;
846                 }
847             }
848         }
849 
850         if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE
851                 && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) {
852             throw new CallStateException("cannot dial in current state");
853         }
854         if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Trying (non-IMS) CS call");
855         return dialInternal(dialString, null, VideoProfile.STATE_AUDIO_ONLY, intentExtras);
856     }
857 
858     @Override
859     protected Connection
dialInternal(String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)860     dialInternal (String dialString, UUSInfo uusInfo, int videoState, Bundle intentExtras)
861             throws CallStateException {
862 
863         // Need to make sure dialString gets parsed properly
864         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
865 
866         // handle in-call MMI first if applicable
867         if (handleInCallMmiCommands(newDialString)) {
868             return null;
869         }
870 
871         // Only look at the Network portion for mmi
872         String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
873         GsmMmiCode mmi =
874                 GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
875         if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
876                                "dialing w/ mmi '" + mmi + "'...");
877 
878         if (mmi == null) {
879             return mCT.dial(newDialString, uusInfo, intentExtras);
880         } else if (mmi.isTemporaryModeCLIR()) {
881             return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo, intentExtras);
882         } else {
883             mPendingMMIs.add(mmi);
884             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
885             mmi.processCode();
886 
887             // FIXME should this return null or something else?
888             return null;
889         }
890     }
891 
892     @Override
handlePinMmi(String dialString)893     public boolean handlePinMmi(String dialString) {
894         GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
895 
896         if (mmi != null && mmi.isPinPukCommand()) {
897             mPendingMMIs.add(mmi);
898             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
899             mmi.processCode();
900             return true;
901         }
902 
903         return false;
904     }
905 
906     @Override
sendUssdResponse(String ussdMessge)907     public void sendUssdResponse(String ussdMessge) {
908         GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
909         mPendingMMIs.add(mmi);
910         mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
911         mmi.sendUssd(ussdMessge);
912     }
913 
914     @Override
915     public void
sendDtmf(char c)916     sendDtmf(char c) {
917         if (!PhoneNumberUtils.is12Key(c)) {
918             Rlog.e(LOG_TAG,
919                     "sendDtmf called with invalid character '" + c + "'");
920         } else {
921             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
922                 mCi.sendDtmf(c, null);
923             }
924         }
925     }
926 
927     @Override
928     public void
startDtmf(char c)929     startDtmf(char c) {
930         if (!PhoneNumberUtils.is12Key(c)) {
931             Rlog.e(LOG_TAG,
932                 "startDtmf called with invalid character '" + c + "'");
933         } else {
934             mCi.startDtmf(c, null);
935         }
936     }
937 
938     @Override
939     public void
stopDtmf()940     stopDtmf() {
941         mCi.stopDtmf(null);
942     }
943 
944     public void
sendBurstDtmf(String dtmfString)945     sendBurstDtmf(String dtmfString) {
946         Rlog.e(LOG_TAG, "[GSMPhone] sendBurstDtmf() is a CDMA method");
947     }
948 
949     @Override
950     public void
setRadioPower(boolean power)951     setRadioPower(boolean power) {
952         mSST.setRadioPower(power);
953     }
954 
storeVoiceMailNumber(String number)955     private void storeVoiceMailNumber(String number) {
956         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
957         SharedPreferences.Editor editor = sp.edit();
958         editor.putString(VM_NUMBER + getPhoneId(), number);
959         editor.apply();
960         setVmSimImsi(getSubscriberId());
961     }
962 
963     @Override
getVoiceMailNumber()964     public String getVoiceMailNumber() {
965         // Read from the SIM. If its null, try reading from the shared preference area.
966         IccRecords r = mIccRecords.get();
967         String number = (r != null) ? r.getVoiceMailNumber() : "";
968         if (TextUtils.isEmpty(number)) {
969             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
970             number = sp.getString(VM_NUMBER + getPhoneId(), null);
971         }
972 
973         if (TextUtils.isEmpty(number)) {
974             String[] listArray = getContext().getResources()
975                 .getStringArray(com.android.internal.R.array.config_default_vm_number);
976             if (listArray != null && listArray.length > 0) {
977                 for (int i=0; i<listArray.length; i++) {
978                     if (!TextUtils.isEmpty(listArray[i])) {
979                         String[] defaultVMNumberArray = listArray[i].split(";");
980                         if (defaultVMNumberArray != null && defaultVMNumberArray.length > 0) {
981                             if (defaultVMNumberArray.length == 1) {
982                                 number = defaultVMNumberArray[0];
983                             } else if (defaultVMNumberArray.length == 2 &&
984                                     !TextUtils.isEmpty(defaultVMNumberArray[1]) &&
985                                     defaultVMNumberArray[1].equalsIgnoreCase(getGroupIdLevel1())) {
986                                 number = defaultVMNumberArray[0];
987                                 break;
988                             }
989                         }
990                     }
991                 }
992             }
993         }
994         return number;
995     }
996 
getVmSimImsi()997     private String getVmSimImsi() {
998         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
999         return sp.getString(VM_SIM_IMSI + getPhoneId(), null);
1000     }
1001 
setVmSimImsi(String imsi)1002     private void setVmSimImsi(String imsi) {
1003         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1004         SharedPreferences.Editor editor = sp.edit();
1005         editor.putString(VM_SIM_IMSI + getPhoneId(), imsi);
1006         editor.apply();
1007     }
1008 
1009     @Override
getVoiceMailAlphaTag()1010     public String getVoiceMailAlphaTag() {
1011         String ret;
1012         IccRecords r = mIccRecords.get();
1013 
1014         ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
1015 
1016         if (ret == null || ret.length() == 0) {
1017             return mContext.getText(
1018                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
1019         }
1020 
1021         return ret;
1022     }
1023 
1024     @Override
getDeviceId()1025     public String getDeviceId() {
1026         return mImei;
1027     }
1028 
1029     @Override
getDeviceSvn()1030     public String getDeviceSvn() {
1031         return mImeiSv;
1032     }
1033 
1034     @Override
getIsimRecords()1035     public IsimRecords getIsimRecords() {
1036         return mIsimUiccRecords;
1037     }
1038 
1039     @Override
getImei()1040     public String getImei() {
1041         return mImei;
1042     }
1043 
1044     @Override
getEsn()1045     public String getEsn() {
1046         Rlog.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method");
1047         return "0";
1048     }
1049 
1050     @Override
getMeid()1051     public String getMeid() {
1052         Rlog.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method");
1053         return "0";
1054     }
1055 
1056     @Override
getNai()1057     public String getNai() {
1058         IccRecords r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP2);
1059         if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
1060             Rlog.v(LOG_TAG, "IccRecords is " + r);
1061         }
1062         return (r != null) ? r.getNAI() : null;
1063     }
1064 
1065     @Override
getSubscriberId()1066     public String getSubscriberId() {
1067         IccRecords r = mIccRecords.get();
1068         return (r != null) ? r.getIMSI() : null;
1069     }
1070 
1071     @Override
getGroupIdLevel1()1072     public String getGroupIdLevel1() {
1073         IccRecords r = mIccRecords.get();
1074         return (r != null) ? r.getGid1() : null;
1075     }
1076 
1077     @Override
getGroupIdLevel2()1078     public String getGroupIdLevel2() {
1079         IccRecords r = mIccRecords.get();
1080         return (r != null) ? r.getGid2() : null;
1081     }
1082 
1083     @Override
getLine1Number()1084     public String getLine1Number() {
1085         IccRecords r = mIccRecords.get();
1086         return (r != null) ? r.getMsisdnNumber() : null;
1087     }
1088 
1089     @Override
getMsisdn()1090     public String getMsisdn() {
1091         IccRecords r = mIccRecords.get();
1092         return (r != null) ? r.getMsisdnNumber() : null;
1093     }
1094 
1095     @Override
getLine1AlphaTag()1096     public String getLine1AlphaTag() {
1097         IccRecords r = mIccRecords.get();
1098         return (r != null) ? r.getMsisdnAlphaTag() : null;
1099     }
1100 
1101     @Override
setLine1Number(String alphaTag, String number, Message onComplete)1102     public boolean setLine1Number(String alphaTag, String number, Message onComplete) {
1103         IccRecords r = mIccRecords.get();
1104         if (r != null) {
1105             r.setMsisdnNumber(alphaTag, number, onComplete);
1106             return true;
1107         } else {
1108             return false;
1109         }
1110     }
1111 
1112     @Override
setVoiceMailNumber(String alphaTag, String voiceMailNumber, Message onComplete)1113     public void setVoiceMailNumber(String alphaTag,
1114                             String voiceMailNumber,
1115                             Message onComplete) {
1116 
1117         Message resp;
1118         mVmNumber = voiceMailNumber;
1119         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
1120         IccRecords r = mIccRecords.get();
1121         if (r != null) {
1122             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
1123         }
1124     }
1125 
isValidCommandInterfaceCFReason(int commandInterfaceCFReason)1126     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
1127         switch (commandInterfaceCFReason) {
1128         case CF_REASON_UNCONDITIONAL:
1129         case CF_REASON_BUSY:
1130         case CF_REASON_NO_REPLY:
1131         case CF_REASON_NOT_REACHABLE:
1132         case CF_REASON_ALL:
1133         case CF_REASON_ALL_CONDITIONAL:
1134             return true;
1135         default:
1136             return false;
1137         }
1138     }
1139 
1140     @Override
getSystemProperty(String property, String defValue)1141     public String getSystemProperty(String property, String defValue) {
1142         if(getUnitTestMode()) {
1143             return null;
1144         }
1145         return TelephonyManager.getTelephonyProperty(mPhoneId, property, defValue);
1146     }
1147 
isValidCommandInterfaceCFAction(int commandInterfaceCFAction)1148     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
1149         switch (commandInterfaceCFAction) {
1150         case CF_ACTION_DISABLE:
1151         case CF_ACTION_ENABLE:
1152         case CF_ACTION_REGISTRATION:
1153         case CF_ACTION_ERASURE:
1154             return true;
1155         default:
1156             return false;
1157         }
1158     }
1159 
updateDataConnectionTracker()1160     public void updateDataConnectionTracker() {
1161         ((DcTracker)mDcTracker).update();
1162     }
1163 
isCfEnable(int action)1164     protected  boolean isCfEnable(int action) {
1165         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
1166     }
1167 
1168     @Override
getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)1169     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
1170         ImsPhone imsPhone = mImsPhone;
1171         if ((imsPhone != null)
1172                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1173             imsPhone.getCallForwardingOption(commandInterfaceCFReason, onComplete);
1174             return;
1175         }
1176 
1177         if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
1178             if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "requesting call forwarding query.");
1179             Message resp;
1180             if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1181                 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
1182             } else {
1183                 resp = onComplete;
1184             }
1185             mCi.queryCallForwardStatus(commandInterfaceCFReason,0,null,resp);
1186         }
1187     }
1188 
1189     @Override
setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)1190     public void setCallForwardingOption(int commandInterfaceCFAction,
1191             int commandInterfaceCFReason,
1192             String dialingNumber,
1193             int timerSeconds,
1194             Message onComplete) {
1195         ImsPhone imsPhone = mImsPhone;
1196         if ((imsPhone != null)
1197                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1198             imsPhone.setCallForwardingOption(commandInterfaceCFAction,
1199                     commandInterfaceCFReason, dialingNumber, timerSeconds, onComplete);
1200             return;
1201         }
1202 
1203         if (    (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
1204                 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
1205 
1206             Message resp;
1207             if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1208                 Cfu cfu = new Cfu(dialingNumber, onComplete);
1209                 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
1210                         isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
1211             } else {
1212                 resp = onComplete;
1213             }
1214             mCi.setCallForward(commandInterfaceCFAction,
1215                     commandInterfaceCFReason,
1216                     CommandsInterface.SERVICE_CLASS_VOICE,
1217                     dialingNumber,
1218                     timerSeconds,
1219                     resp);
1220         }
1221     }
1222 
1223     @Override
getOutgoingCallerIdDisplay(Message onComplete)1224     public void getOutgoingCallerIdDisplay(Message onComplete) {
1225         mCi.getCLIR(onComplete);
1226     }
1227 
1228     @Override
setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete)1229     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
1230                                            Message onComplete) {
1231         mCi.setCLIR(commandInterfaceCLIRMode,
1232                 obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
1233     }
1234 
1235     @Override
getCallWaiting(Message onComplete)1236     public void getCallWaiting(Message onComplete) {
1237         ImsPhone imsPhone = mImsPhone;
1238         if ((imsPhone != null)
1239                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1240             imsPhone.getCallWaiting(onComplete);
1241             return;
1242         }
1243 
1244         //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
1245         //class parameter in call waiting interrogation  to network
1246         mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
1247     }
1248 
1249     @Override
setCallWaiting(boolean enable, Message onComplete)1250     public void setCallWaiting(boolean enable, Message onComplete) {
1251         ImsPhone imsPhone = mImsPhone;
1252         if ((imsPhone != null)
1253                 && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1254             imsPhone.setCallWaiting(enable, onComplete);
1255             return;
1256         }
1257 
1258         mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1259     }
1260 
1261     @Override
1262     public void
getAvailableNetworks(Message response)1263     getAvailableNetworks(Message response) {
1264         mCi.getAvailableNetworks(response);
1265     }
1266 
1267     @Override
1268     public void
getNeighboringCids(Message response)1269     getNeighboringCids(Message response) {
1270         mCi.getNeighboringCids(response);
1271     }
1272 
1273     @Override
setOnPostDialCharacter(Handler h, int what, Object obj)1274     public void setOnPostDialCharacter(Handler h, int what, Object obj) {
1275         mPostDialHandler = new Registrant(h, what, obj);
1276     }
1277 
1278     @Override
setUiTTYMode(int uiTtyMode, Message onComplete)1279     public void setUiTTYMode(int uiTtyMode, Message onComplete) {
1280        if (mImsPhone != null) {
1281            mImsPhone.setUiTTYMode(uiTtyMode, onComplete);
1282        }
1283     }
1284 
1285     @Override
setMute(boolean muted)1286     public void setMute(boolean muted) {
1287         mCT.setMute(muted);
1288     }
1289 
1290     @Override
getMute()1291     public boolean getMute() {
1292         return mCT.getMute();
1293     }
1294 
1295     @Override
getDataCallList(Message response)1296     public void getDataCallList(Message response) {
1297         mCi.getDataCallList(response);
1298     }
1299 
1300     @Override
updateServiceLocation()1301     public void updateServiceLocation() {
1302         mSST.enableSingleLocationUpdate();
1303     }
1304 
1305     @Override
enableLocationUpdates()1306     public void enableLocationUpdates() {
1307         mSST.enableLocationUpdates();
1308     }
1309 
1310     @Override
disableLocationUpdates()1311     public void disableLocationUpdates() {
1312         mSST.disableLocationUpdates();
1313     }
1314 
1315     @Override
getDataRoamingEnabled()1316     public boolean getDataRoamingEnabled() {
1317         return mDcTracker.getDataOnRoamingEnabled();
1318     }
1319 
1320     @Override
setDataRoamingEnabled(boolean enable)1321     public void setDataRoamingEnabled(boolean enable) {
1322         mDcTracker.setDataOnRoamingEnabled(enable);
1323     }
1324 
1325     @Override
getDataEnabled()1326     public boolean getDataEnabled() {
1327         return mDcTracker.getDataEnabled();
1328     }
1329 
1330     @Override
setDataEnabled(boolean enable)1331     public void setDataEnabled(boolean enable) {
1332         mDcTracker.setDataEnabled(enable);
1333     }
1334 
1335     /**
1336      * Removes the given MMI from the pending list and notifies
1337      * registrants that it is complete.
1338      * @param mmi MMI that is done
1339      */
1340     /*package*/ void
onMMIDone(GsmMmiCode mmi)1341     onMMIDone(GsmMmiCode mmi) {
1342         /* Only notify complete if it's on the pending list.
1343          * Otherwise, it's already been handled (eg, previously canceled).
1344          * The exception is cancellation of an incoming USSD-REQUEST, which is
1345          * not on the list.
1346          */
1347         if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest() || mmi.isSsInfo()) {
1348             mMmiCompleteRegistrants.notifyRegistrants(
1349                 new AsyncResult(null, mmi, null));
1350         }
1351     }
1352 
1353 
1354     private void
onNetworkInitiatedUssd(GsmMmiCode mmi)1355     onNetworkInitiatedUssd(GsmMmiCode mmi) {
1356         mMmiCompleteRegistrants.notifyRegistrants(
1357             new AsyncResult(null, mmi, null));
1358     }
1359 
1360 
1361     /** ussdMode is one of CommandsInterface.USSD_MODE_* */
1362     private void
onIncomingUSSD(int ussdMode, String ussdMessage)1363     onIncomingUSSD (int ussdMode, String ussdMessage) {
1364         boolean isUssdError;
1365         boolean isUssdRequest;
1366         boolean isUssdRelease;
1367 
1368         isUssdRequest
1369             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
1370 
1371         isUssdError
1372             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
1373                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
1374 
1375         isUssdRelease = (ussdMode == CommandsInterface.USSD_MODE_NW_RELEASE);
1376 
1377         // See comments in GsmMmiCode.java
1378         // USSD requests aren't finished until one
1379         // of these two events happen
1380         GsmMmiCode found = null;
1381         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
1382             if(mPendingMMIs.get(i).isPendingUSSD()) {
1383                 found = mPendingMMIs.get(i);
1384                 break;
1385             }
1386         }
1387 
1388         if (found != null) {
1389             // Complete pending USSD
1390 
1391             if (isUssdRelease) {
1392                 found.onUssdRelease();
1393             } else if (isUssdError) {
1394                 found.onUssdFinishedError();
1395             } else {
1396                 found.onUssdFinished(ussdMessage, isUssdRequest);
1397             }
1398         } else { // pending USSD not found
1399             // The network may initiate its own USSD request
1400 
1401             // ignore everything that isnt a Notify or a Request
1402             // also, discard if there is no message to present
1403             if (!isUssdError && ussdMessage != null) {
1404                 GsmMmiCode mmi;
1405                 mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
1406                                                    isUssdRequest,
1407                                                    GSMPhone.this,
1408                                                    mUiccApplication.get());
1409                 onNetworkInitiatedUssd(mmi);
1410             }
1411         }
1412     }
1413 
1414     /**
1415      * Make sure the network knows our preferred setting.
1416      */
syncClirSetting()1417     protected  void syncClirSetting() {
1418         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1419         int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
1420         if (clirSetting >= 0) {
1421             mCi.setCLIR(clirSetting, null);
1422         }
1423     }
1424 
1425     @Override
handleMessage(Message msg)1426     public void handleMessage (Message msg) {
1427         AsyncResult ar;
1428         Message onComplete;
1429 
1430         // messages to be handled whether or not the phone is being destroyed
1431         // should only include messages which are being re-directed and do not use
1432         // resources of the phone being destroyed
1433         switch (msg.what) {
1434             // handle the select network completion callbacks.
1435             case EVENT_SET_NETWORK_MANUAL_COMPLETE:
1436             case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
1437                 super.handleMessage(msg);
1438                 return;
1439         }
1440 
1441         if (!mIsTheCurrentActivePhone) {
1442             Rlog.e(LOG_TAG, "Received message " + msg +
1443                     "[" + msg.what + "] while being destroyed. Ignoring.");
1444             return;
1445         }
1446         switch (msg.what) {
1447             case EVENT_RADIO_AVAILABLE: {
1448                 mCi.getBasebandVersion(
1449                         obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
1450 
1451                 mCi.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
1452                 mCi.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
1453                 mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
1454                 startLceAfterRadioIsAvailable();
1455             }
1456             break;
1457 
1458             case EVENT_RADIO_ON:
1459                 // If this is on APM off, SIM may already be loaded. Send setPreferredNetworkType
1460                 // request to RIL to preserve user setting across APM toggling
1461                 setPreferredNetworkTypeIfSimLoaded();
1462                 break;
1463 
1464             case EVENT_REGISTERED_TO_NETWORK:
1465                 syncClirSetting();
1466                 break;
1467 
1468             case EVENT_SIM_RECORDS_LOADED:
1469                 updateCurrentCarrierInProvider();
1470 
1471                 // Check if this is a different SIM than the previous one. If so unset the
1472                 // voice mail number.
1473                 String imsi = getVmSimImsi();
1474                 String imsiFromSIM = getSubscriberId();
1475                 if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
1476                     storeVoiceMailNumber(null);
1477                     setVmSimImsi(null);
1478                 }
1479 
1480                 mSimRecordsLoadedRegistrants.notifyRegistrants();
1481                 updateVoiceMail();
1482             break;
1483 
1484             case EVENT_GET_BASEBAND_VERSION_DONE:
1485                 ar = (AsyncResult)msg.obj;
1486 
1487                 if (ar.exception != null) {
1488                     break;
1489                 }
1490 
1491                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Baseband version: " + ar.result);
1492                 TelephonyManager.from(mContext).setBasebandVersionForPhone(getPhoneId(),
1493                         (String)ar.result);
1494             break;
1495 
1496             case EVENT_GET_IMEI_DONE:
1497                 ar = (AsyncResult)msg.obj;
1498 
1499                 if (ar.exception != null) {
1500                     break;
1501                 }
1502 
1503                 mImei = (String)ar.result;
1504             break;
1505 
1506             case EVENT_GET_IMEISV_DONE:
1507                 ar = (AsyncResult)msg.obj;
1508 
1509                 if (ar.exception != null) {
1510                     break;
1511                 }
1512 
1513                 mImeiSv = (String)ar.result;
1514             break;
1515 
1516             case EVENT_USSD:
1517                 ar = (AsyncResult)msg.obj;
1518 
1519                 String[] ussdResult = (String[]) ar.result;
1520 
1521                 if (ussdResult.length > 1) {
1522                     try {
1523                         onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
1524                     } catch (NumberFormatException e) {
1525                         Rlog.w(LOG_TAG, "error parsing USSD");
1526                     }
1527                 }
1528             break;
1529 
1530             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: {
1531                 // Some MMI requests (eg USSD) are not completed
1532                 // within the course of a CommandsInterface request
1533                 // If the radio shuts off or resets while one of these
1534                 // is pending, we need to clean up.
1535 
1536                 for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
1537                     if (mPendingMMIs.get(i).isPendingUSSD()) {
1538                         mPendingMMIs.get(i).onUssdFinishedError();
1539                     }
1540                 }
1541                 ImsPhone imsPhone = mImsPhone;
1542                 if (imsPhone != null) {
1543                     imsPhone.getServiceState().setStateOff();
1544                 }
1545                 mRadioOffOrNotAvailableRegistrants.notifyRegistrants();
1546                 break;
1547             }
1548 
1549             case EVENT_SSN:
1550                 ar = (AsyncResult)msg.obj;
1551                 SuppServiceNotification not = (SuppServiceNotification) ar.result;
1552                 mSsnRegistrants.notifyRegistrants(ar);
1553             break;
1554 
1555             case EVENT_SET_CALL_FORWARD_DONE:
1556                 ar = (AsyncResult)msg.obj;
1557                 IccRecords r = mIccRecords.get();
1558                 Cfu cfu = (Cfu) ar.userObj;
1559                 if (ar.exception == null && r != null) {
1560                     r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
1561                 }
1562                 if (cfu.mOnComplete != null) {
1563                     AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
1564                     cfu.mOnComplete.sendToTarget();
1565                 }
1566                 break;
1567 
1568             case EVENT_SET_VM_NUMBER_DONE:
1569                 ar = (AsyncResult)msg.obj;
1570                 if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
1571                     storeVoiceMailNumber(mVmNumber);
1572                     ar.exception = null;
1573                 }
1574                 onComplete = (Message) ar.userObj;
1575                 if (onComplete != null) {
1576                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1577                     onComplete.sendToTarget();
1578                 }
1579                 break;
1580 
1581 
1582             case EVENT_GET_CALL_FORWARD_DONE:
1583                 ar = (AsyncResult)msg.obj;
1584                 if (ar.exception == null) {
1585                     handleCfuQueryResult((CallForwardInfo[])ar.result);
1586                 }
1587                 onComplete = (Message) ar.userObj;
1588                 if (onComplete != null) {
1589                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1590                     onComplete.sendToTarget();
1591                 }
1592                 break;
1593 
1594             case EVENT_SET_NETWORK_AUTOMATIC:
1595                 // Automatic network selection from EF_CSP SIM record
1596                 ar = (AsyncResult) msg.obj;
1597                 if (mSST.mSS.getIsManualSelection()) {
1598                     setNetworkSelectionModeAutomatic((Message) ar.result);
1599                     Rlog.d(LOG_TAG, "SET_NETWORK_SELECTION_AUTOMATIC: set to automatic");
1600                 } else {
1601                     // prevent duplicate request which will push current PLMN to low priority
1602                     Rlog.d(LOG_TAG, "SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore");
1603                 }
1604                 break;
1605 
1606             case EVENT_ICC_RECORD_EVENTS:
1607                 ar = (AsyncResult)msg.obj;
1608                 processIccRecordEvents((Integer)ar.result);
1609                 break;
1610 
1611             case EVENT_SET_CLIR_COMPLETE:
1612                 ar = (AsyncResult)msg.obj;
1613                 if (ar.exception == null) {
1614                     saveClirSetting(msg.arg1);
1615                 }
1616                 onComplete = (Message) ar.userObj;
1617                 if (onComplete != null) {
1618                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1619                     onComplete.sendToTarget();
1620                 }
1621                 break;
1622 
1623             case EVENT_SS:
1624                 ar = (AsyncResult)msg.obj;
1625                 Rlog.d(LOG_TAG, "Event EVENT_SS received");
1626                 // SS data is already being handled through MMI codes.
1627                 // So, this result if processed as MMI response would help
1628                 // in re-using the existing functionality.
1629                 GsmMmiCode mmi = new GsmMmiCode(this, mUiccApplication.get());
1630                 mmi.processSsData(ar);
1631                 break;
1632 
1633              default:
1634                  super.handleMessage(msg);
1635         }
1636     }
1637 
getUiccCardApplication()1638     protected UiccCardApplication getUiccCardApplication() {
1639             return  mUiccController.getUiccCardApplication(mPhoneId,
1640                     UiccController.APP_FAM_3GPP);
1641     }
1642 
1643     @Override
onUpdateIccAvailability()1644     protected void onUpdateIccAvailability() {
1645         if (mUiccController == null ) {
1646             return;
1647         }
1648 
1649         UiccCardApplication newUiccApplication =
1650                 mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS);
1651         IsimUiccRecords newIsimUiccRecords = null;
1652 
1653         if (newUiccApplication != null) {
1654             newIsimUiccRecords = (IsimUiccRecords)newUiccApplication.getIccRecords();
1655             if (LOCAL_DEBUG) log("New ISIM application found");
1656         }
1657         mIsimUiccRecords = newIsimUiccRecords;
1658 
1659         newUiccApplication = getUiccCardApplication();
1660 
1661         UiccCardApplication app = mUiccApplication.get();
1662         if (app != newUiccApplication) {
1663             if (app != null) {
1664                 if (LOCAL_DEBUG) log("Removing stale icc objects.");
1665                 if (mIccRecords.get() != null) {
1666                     unregisterForSimRecordEvents();
1667                     mSimPhoneBookIntManager.updateIccRecords(null);
1668                 }
1669                 mIccRecords.set(null);
1670                 mUiccApplication.set(null);
1671             }
1672             if (newUiccApplication != null) {
1673                 if (LOCAL_DEBUG) log("New Uicc application found");
1674                 mUiccApplication.set(newUiccApplication);
1675                 mIccRecords.set(newUiccApplication.getIccRecords());
1676                 registerForSimRecordEvents();
1677                 mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get());
1678             }
1679         }
1680     }
1681 
processIccRecordEvents(int eventCode)1682     private void processIccRecordEvents(int eventCode) {
1683         switch (eventCode) {
1684             case IccRecords.EVENT_CFI:
1685                 notifyCallForwardingIndicator();
1686                 break;
1687         }
1688     }
1689 
1690     /**
1691      * Sets the "current" field in the telephony provider according to the SIM's operator
1692      *
1693      * @return true for success; false otherwise.
1694      */
updateCurrentCarrierInProvider()1695     public boolean updateCurrentCarrierInProvider() {
1696         long currentDds = SubscriptionManager.getDefaultDataSubId();
1697         String operatorNumeric = getOperatorNumeric();
1698 
1699         log("updateCurrentCarrierInProvider: mSubId = " + getSubId()
1700                 + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric);
1701 
1702         if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) {
1703             try {
1704                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
1705                 ContentValues map = new ContentValues();
1706                 map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
1707                 mContext.getContentResolver().insert(uri, map);
1708                 return true;
1709             } catch (SQLException e) {
1710                 Rlog.e(LOG_TAG, "Can't store current operator", e);
1711             }
1712         }
1713         return false;
1714     }
1715 
1716     /**
1717      * Saves CLIR setting so that we can re-apply it as necessary
1718      * (in case the RIL resets it across reboots).
1719      */
saveClirSetting(int commandInterfaceCLIRMode)1720     public void saveClirSetting(int commandInterfaceCLIRMode) {
1721         // open the shared preferences editor, and write the value.
1722         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1723         SharedPreferences.Editor editor = sp.edit();
1724         editor.putInt(CLIR_KEY + getPhoneId(), commandInterfaceCLIRMode);
1725 
1726         // commit and log the result.
1727         if (! editor.commit()) {
1728             Rlog.e(LOG_TAG, "failed to commit CLIR preference");
1729         }
1730     }
1731 
handleCfuQueryResult(CallForwardInfo[] infos)1732     private void handleCfuQueryResult(CallForwardInfo[] infos) {
1733         IccRecords r = mIccRecords.get();
1734         if (r != null) {
1735             if (infos == null || infos.length == 0) {
1736                 // Assume the default is not active
1737                 // Set unconditional CFF in SIM to false
1738                 r.setVoiceCallForwardingFlag(1, false, null);
1739             } else {
1740                 for (int i = 0, s = infos.length; i < s; i++) {
1741                     if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
1742                         r.setVoiceCallForwardingFlag(1, (infos[i].status == 1),
1743                             infos[i].number);
1744                         // should only have the one
1745                         break;
1746                     }
1747                 }
1748             }
1749         }
1750     }
1751 
1752     /**
1753      * Retrieves the PhoneSubInfo of the GSMPhone
1754      */
1755     @Override
getPhoneSubInfo()1756     public PhoneSubInfo getPhoneSubInfo(){
1757         return mSubInfo;
1758     }
1759 
1760     /**
1761      * Retrieves the IccPhoneBookInterfaceManager of the GSMPhone
1762      */
1763     @Override
getIccPhoneBookInterfaceManager()1764     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
1765         return mSimPhoneBookIntManager;
1766     }
1767 
1768     /**
1769      * Activate or deactivate cell broadcast SMS.
1770      *
1771      * @param activate 0 = activate, 1 = deactivate
1772      * @param response Callback message is empty on completion
1773      */
1774     @Override
activateCellBroadcastSms(int activate, Message response)1775     public void activateCellBroadcastSms(int activate, Message response) {
1776         Rlog.e(LOG_TAG, "[GSMPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
1777         response.sendToTarget();
1778     }
1779 
1780     /**
1781      * Query the current configuration of cdma cell broadcast SMS.
1782      *
1783      * @param response Callback message is empty on completion
1784      */
1785     @Override
getCellBroadcastSmsConfig(Message response)1786     public void getCellBroadcastSmsConfig(Message response) {
1787         Rlog.e(LOG_TAG, "[GSMPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
1788         response.sendToTarget();
1789     }
1790 
1791     /**
1792      * Configure cdma cell broadcast SMS.
1793      *
1794      * @param response Callback message is empty on completion
1795      */
1796     @Override
setCellBroadcastSmsConfig(int[] configValuesArray, Message response)1797     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
1798         Rlog.e(LOG_TAG, "[GSMPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
1799         response.sendToTarget();
1800     }
1801 
1802     @Override
isCspPlmnEnabled()1803     public boolean isCspPlmnEnabled() {
1804         IccRecords r = mIccRecords.get();
1805         return (r != null) ? r.isCspPlmnEnabled() : false;
1806     }
1807 
isManualNetSelAllowed()1808     boolean isManualNetSelAllowed() {
1809 
1810         int nwMode = Phone.PREFERRED_NT_MODE;
1811         int subId = getSubId();
1812 
1813         nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(),
1814                     android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode);
1815 
1816         Rlog.d(LOG_TAG, "isManualNetSelAllowed in mode = " + nwMode);
1817         /*
1818          *  For multimode targets in global mode manual network
1819          *  selection is disallowed
1820          */
1821         if (isManualSelProhibitedInGlobalMode()
1822                 && ((nwMode == Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
1823                         || (nwMode == Phone.NT_MODE_GLOBAL)) ){
1824             Rlog.d(LOG_TAG, "Manual selection not supported in mode = " + nwMode);
1825             return false;
1826         } else {
1827             Rlog.d(LOG_TAG, "Manual selection is supported in mode = " + nwMode);
1828         }
1829 
1830         /*
1831          *  Single mode phone with - GSM network modes/global mode
1832          *  LTE only for 3GPP
1833          *  LTE centric + 3GPP Legacy
1834          *  Note: the actual enabling/disabling manual selection for these
1835          *  cases will be controlled by csp
1836          */
1837         return true;
1838     }
1839 
isManualSelProhibitedInGlobalMode()1840     private boolean isManualSelProhibitedInGlobalMode() {
1841         boolean isProhibited = false;
1842         final String configString = getContext().getResources().getString(com.android.internal.
1843                                             R.string.prohibit_manual_network_selection_in_gobal_mode);
1844 
1845         if (!TextUtils.isEmpty(configString)) {
1846             String[] configArray = configString.split(";");
1847 
1848             if (configArray != null &&
1849                     ((configArray.length == 1 && configArray[0].equalsIgnoreCase("true")) ||
1850                         (configArray.length == 2 && !TextUtils.isEmpty(configArray[1]) &&
1851                             configArray[0].equalsIgnoreCase("true") &&
1852                             configArray[1].equalsIgnoreCase(getGroupIdLevel1())))) {
1853                             isProhibited = true;
1854             }
1855         }
1856         Rlog.d(LOG_TAG, "isManualNetSelAllowedInGlobal in current carrier is " + isProhibited);
1857         return isProhibited;
1858     }
1859 
registerForSimRecordEvents()1860     private void registerForSimRecordEvents() {
1861         IccRecords r = mIccRecords.get();
1862         if (r == null) {
1863             return;
1864         }
1865         r.registerForNetworkSelectionModeAutomatic(
1866                 this, EVENT_SET_NETWORK_AUTOMATIC, null);
1867         r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
1868         r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
1869     }
1870 
unregisterForSimRecordEvents()1871     private void unregisterForSimRecordEvents() {
1872         IccRecords r = mIccRecords.get();
1873         if (r == null) {
1874             return;
1875         }
1876         r.unregisterForNetworkSelectionModeAutomatic(this);
1877         r.unregisterForRecordsEvents(this);
1878         r.unregisterForRecordsLoaded(this);
1879     }
1880 
1881     @Override
exitEmergencyCallbackMode()1882     public void exitEmergencyCallbackMode() {
1883         if (mImsPhone != null) {
1884             mImsPhone.exitEmergencyCallbackMode();
1885         }
1886     }
1887 
1888     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1889     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1890         pw.println("GSMPhone extends:");
1891         super.dump(fd, pw, args);
1892         pw.println(" mCT=" + mCT);
1893         pw.println(" mSST=" + mSST);
1894         pw.println(" mPendingMMIs=" + mPendingMMIs);
1895         pw.println(" mSimPhoneBookIntManager=" + mSimPhoneBookIntManager);
1896         pw.println(" mSubInfo=" + mSubInfo);
1897         if (VDBG) pw.println(" mImei=" + mImei);
1898         if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
1899         pw.println(" mVmNumber=" + mVmNumber);
1900     }
1901 
1902     @Override
setOperatorBrandOverride(String brand)1903     public boolean setOperatorBrandOverride(String brand) {
1904         if (mUiccController == null) {
1905             return false;
1906         }
1907 
1908         UiccCard card = mUiccController.getUiccCard(getPhoneId());
1909         if (card == null) {
1910             return false;
1911         }
1912 
1913         boolean status = card.setOperatorBrandOverride(brand);
1914 
1915         // Refresh.
1916         if (status) {
1917             IccRecords iccRecords = mIccRecords.get();
1918             if (iccRecords != null) {
1919                 TelephonyManager.from(mContext).setSimOperatorNameForPhone(
1920                         getPhoneId(), iccRecords.getServiceProviderName());
1921             }
1922             if (mSST != null) {
1923                 mSST.pollState();
1924             }
1925         }
1926         return status;
1927     }
1928 
1929     /**
1930      * @return operator numeric.
1931      */
getOperatorNumeric()1932     public String getOperatorNumeric() {
1933         String operatorNumeric = null;
1934         IccRecords r = mIccRecords.get();
1935         if (r != null) {
1936             operatorNumeric = r.getOperatorNumeric();
1937         }
1938         return operatorNumeric;
1939     }
1940 
registerForAllDataDisconnected(Handler h, int what, Object obj)1941     public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
1942         ((DcTracker)mDcTracker)
1943                 .registerForAllDataDisconnected(h, what, obj);
1944     }
1945 
unregisterForAllDataDisconnected(Handler h)1946     public void unregisterForAllDataDisconnected(Handler h) {
1947         ((DcTracker)mDcTracker).unregisterForAllDataDisconnected(h);
1948     }
1949 
setInternalDataEnabled(boolean enable, Message onCompleteMsg)1950     public void setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
1951         ((DcTracker)mDcTracker)
1952                 .setInternalDataEnabled(enable, onCompleteMsg);
1953     }
1954 
1955 
setInternalDataEnabledFlag(boolean enable)1956     public boolean setInternalDataEnabledFlag(boolean enable) {
1957         return ((DcTracker)mDcTracker)
1958                 .setInternalDataEnabledFlag(enable);
1959     }
1960 
notifyEcbmTimerReset(Boolean flag)1961     public void notifyEcbmTimerReset(Boolean flag) {
1962         mEcmTimerResetRegistrants.notifyResult(flag);
1963     }
1964 
1965     /**
1966      * Registration point for Ecm timer reset
1967      *
1968      * @param h handler to notify
1969      * @param what User-defined message code
1970      * @param obj placed in Message.obj
1971      */
1972     @Override
registerForEcmTimerReset(Handler h, int what, Object obj)1973     public void registerForEcmTimerReset(Handler h, int what, Object obj) {
1974         mEcmTimerResetRegistrants.addUnique(h, what, obj);
1975     }
1976 
1977     @Override
unregisterForEcmTimerReset(Handler h)1978     public void unregisterForEcmTimerReset(Handler h) {
1979         mEcmTimerResetRegistrants.remove(h);
1980     }
1981 
1982     /**
1983      * Sets the SIM voice message waiting indicator records.
1984      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
1985      * @param countWaiting The number of messages waiting, if known. Use
1986      *                     -1 to indicate that an unknown number of
1987      *                      messages are waiting
1988      */
1989     @Override
setVoiceMessageWaiting(int line, int countWaiting)1990     public void setVoiceMessageWaiting(int line, int countWaiting) {
1991         IccRecords r = mIccRecords.get();
1992         if (r != null) {
1993             r.setVoiceMessageWaiting(line, countWaiting);
1994         } else {
1995             log("SIM Records not found, MWI not updated");
1996         }
1997     }
1998 
log(String s)1999     protected void log(String s) {
2000         Rlog.d(LOG_TAG, "[GSMPhone] " + s);
2001     }
2002 }
2003