a7991efb6e497d9c283eb84015c06e86d5ce7c0b
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / gsm / GSMPhone.java
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package com.android.internal.telephony.gsm;
19
20 import android.content.ContentValues;
21 import android.content.Context;
22 import android.content.SharedPreferences;
23 import android.database.SQLException;
24 import android.net.Uri;
25 import android.os.AsyncResult;
26 import android.os.Handler;
27 import android.os.Message;
28 import android.os.Registrant;
29 import android.os.RegistrantList;
30 import android.os.SystemProperties;
31 import android.preference.PreferenceManager;
32 import android.provider.Telephony;
33 import android.telephony.CellLocation;
34 import android.telephony.PhoneNumberUtils;
35 import android.telephony.ServiceState;
36 import com.android.internal.telephony.CallTracker;
37 import android.text.TextUtils;
38 import android.telephony.Rlog;
39
40 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
41 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
42 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
43 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
44 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
45 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
46 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
47 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
48 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
49 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
50 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
51 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
52
53 import com.android.internal.telephony.SmsBroadcastUndelivered;
54 import com.android.internal.telephony.dataconnection.DcTracker;
55 import com.android.internal.telephony.CallForwardInfo;
56 import com.android.internal.telephony.CallStateException;
57 import com.android.internal.telephony.CommandsInterface;
58 import com.android.internal.telephony.Connection;
59 import com.android.internal.telephony.IccPhoneBookInterfaceManager;
60 import com.android.internal.telephony.IccSmsInterfaceManager;
61 import com.android.internal.telephony.MmiCode;
62 import com.android.internal.telephony.OperatorInfo;
63 import com.android.internal.telephony.Phone;
64 import com.android.internal.telephony.PhoneBase;
65 import com.android.internal.telephony.PhoneConstants;
66 import com.android.internal.telephony.PhoneNotifier;
67 import com.android.internal.telephony.PhoneProxy;
68 import com.android.internal.telephony.PhoneSubInfo;
69 import com.android.internal.telephony.TelephonyProperties;
70 import com.android.internal.telephony.UUSInfo;
71 import com.android.internal.telephony.test.SimulatedRadioControl;
72 import com.android.internal.telephony.uicc.IccRecords;
73 import com.android.internal.telephony.uicc.IccVmNotSupportedException;
74 import com.android.internal.telephony.uicc.UiccCardApplication;
75 import com.android.internal.telephony.uicc.UiccController;
76 import com.android.internal.telephony.ServiceStateTracker;
77
78 import java.io.FileDescriptor;
79 import java.io.IOException;
80 import java.io.PrintWriter;
81 import java.net.InetSocketAddress;
82 import java.net.ServerSocket;
83 import java.net.Socket;
84 import java.util.ArrayList;
85 import java.util.List;
86
87 /**
88  * {@hide}
89  */
90 public class GSMPhone extends PhoneBase {
91     // NOTE that LOG_TAG here is "GSM", which means that log messages
92     // from this file will go into the radio log rather than the main
93     // log.  (Use "adb logcat -b radio" to see them.)
94     static final String LOG_TAG = "GSMPhone";
95     private static final boolean LOCAL_DEBUG = true;
96     private static final boolean VDBG = false; /* STOPSHIP if true */
97     private static final boolean DBG_PORT = false; /* STOPSHIP if true */
98
99     // Key used to read/write current ciphering state
100     public static final String CIPHERING_KEY = "ciphering_key";
101     // Key used to read/write voice mail number
102     public static final String VM_NUMBER = "vm_number_key";
103     // Key used to read/write the SIM IMSI used for storing the voice mail
104     public static final String VM_SIM_IMSI = "vm_sim_imsi_key";
105
106     // Instance Variables
107     GsmCallTracker mCT;
108     GsmServiceStateTracker mSST;
109     ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>();
110     SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
111     PhoneSubInfo mSubInfo;
112
113
114     Registrant mPostDialHandler;
115
116     /** List of Registrants to receive Supplementary Service Notifications. */
117     RegistrantList mSsnRegistrants = new RegistrantList();
118
119     Thread mDebugPortThread;
120     ServerSocket mDebugSocket;
121
122     private String mImei;
123     private String mImeiSv;
124     private String mVmNumber;
125
126     GsmInboundSmsHandler mGsmInboundSmsHandler;
127
128     // Create Cfu (Call forward unconditional) so that dialling number &
129     // mOnComplete (Message object passed by client) can be packed &
130     // given as a single Cfu object as user data to RIL.
131     private static class Cfu {
132         final String mSetCfNumber;
133         final Message mOnComplete;
134
135         Cfu(String cfNumber, Message onComplete) {
136             mSetCfNumber = cfNumber;
137             mOnComplete = onComplete;
138         }
139     }
140
141     // Constructors
142
143     public
144     GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) {
145         this(context,ci,notifier, false);
146     }
147
148     public
149     GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
150         super("GSM", notifier, context, ci, unitTestMode);
151
152         if (ci instanceof SimulatedRadioControl) {
153             mSimulatedRadioControl = (SimulatedRadioControl) ci;
154         }
155
156         mCi.setPhoneType(PhoneConstants.PHONE_TYPE_GSM);
157         mCT = new GsmCallTracker(this);
158         mSST = new GsmServiceStateTracker (this);
159
160         mDcTracker = new DcTracker(this);
161         if (!unitTestMode) {
162             mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
163             mSubInfo = new PhoneSubInfo(this);
164         }
165
166         mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
167         mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
168         mCi.registerForOn(this, EVENT_RADIO_ON, null);
169         mCi.setOnUSSD(this, EVENT_USSD, null);
170         mCi.setOnSuppServiceNotification(this, EVENT_SSN, null);
171         mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
172
173         if (DBG_PORT) {
174             try {
175                 //debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");
176                 mDebugSocket = new ServerSocket();
177                 mDebugSocket.setReuseAddress(true);
178                 mDebugSocket.bind (new InetSocketAddress("127.0.0.1", 6666));
179
180                 mDebugPortThread
181                     = new Thread(
182                         new Runnable() {
183                             @Override
184                             public void run() {
185                                 for(;;) {
186                                     try {
187                                         Socket sock;
188                                         sock = mDebugSocket.accept();
189                                         Rlog.i(LOG_TAG, "New connection; resetting radio");
190                                         mCi.resetRadio(null);
191                                         sock.close();
192                                     } catch (IOException ex) {
193                                         Rlog.w(LOG_TAG,
194                                             "Exception accepting socket", ex);
195                                     }
196                                 }
197                             }
198                         },
199                         "GSMPhone debug");
200
201                 mDebugPortThread.start();
202
203             } catch (IOException ex) {
204                 Rlog.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex);
205             }
206         }
207
208         //Change the system property
209         SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
210                 new Integer(PhoneConstants.PHONE_TYPE_GSM).toString());
211     }
212
213     @Override
214     public void dispose() {
215         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
216             super.dispose();
217
218             //Unregister from all former registered events
219             mCi.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE
220             unregisterForSimRecordEvents();
221             mCi.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
222             mCi.unregisterForOn(this); //EVENT_RADIO_ON
223             mSST.unregisterForNetworkAttached(this); //EVENT_REGISTERED_TO_NETWORK
224             mCi.unSetOnUSSD(this);
225             mCi.unSetOnSuppServiceNotification(this);
226
227             mPendingMMIs.clear();
228
229             //Force all referenced classes to unregister their former registered events
230             mCT.dispose();
231             mDcTracker.dispose();
232             mSST.dispose();
233             mSimPhoneBookIntManager.dispose();
234             mSubInfo.dispose();
235         }
236     }
237
238     @Override
239     public void removeReferences() {
240         Rlog.d(LOG_TAG, "removeReferences");
241         mSimulatedRadioControl = null;
242         mSimPhoneBookIntManager = null;
243         mSubInfo = null;
244         mCT = null;
245         mSST = null;
246         super.removeReferences();
247     }
248
249     @Override
250     protected void finalize() {
251         if(LOCAL_DEBUG) Rlog.d(LOG_TAG, "GSMPhone finalized");
252     }
253
254
255     @Override
256     public ServiceState
257     getServiceState() {
258         return mSST.mSS;
259     }
260
261     @Override
262     public CellLocation getCellLocation() {
263         return mSST.getCellLocation();
264     }
265
266     @Override
267     public PhoneConstants.State getState() {
268         return mCT.mState;
269     }
270
271     @Override
272     public int getPhoneType() {
273         return PhoneConstants.PHONE_TYPE_GSM;
274     }
275
276     @Override
277     public ServiceStateTracker getServiceStateTracker() {
278         return mSST;
279     }
280
281     @Override
282     public CallTracker getCallTracker() {
283         return mCT;
284     }
285
286     @Override
287     public List<? extends MmiCode>
288     getPendingMmiCodes() {
289         return mPendingMMIs;
290     }
291
292     @Override
293     public PhoneConstants.DataState getDataConnectionState(String apnType) {
294         PhoneConstants.DataState ret = PhoneConstants.DataState.DISCONNECTED;
295
296         if (mSST == null) {
297             // Radio Technology Change is ongoning, dispose() and removeReferences() have
298             // already been called
299
300             ret = PhoneConstants.DataState.DISCONNECTED;
301         } else if (mSST.getCurrentDataConnectionState()
302                 != ServiceState.STATE_IN_SERVICE) {
303             // If we're out of service, open TCP sockets may still work
304             // but no data will flow
305             ret = PhoneConstants.DataState.DISCONNECTED;
306         } else if (mDcTracker.isApnTypeEnabled(apnType) == false ||
307                 mDcTracker.isApnTypeActive(apnType) == false) {
308             //TODO: isApnTypeActive() is just checking whether ApnContext holds
309             //      Dataconnection or not. Checking each ApnState below should
310             //      provide the same state. Calling isApnTypeActive() can be removed.
311             ret = PhoneConstants.DataState.DISCONNECTED;
312         } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
313             switch (mDcTracker.getState(apnType)) {
314                 case RETRYING:
315                 case FAILED:
316                 case IDLE:
317                     ret = PhoneConstants.DataState.DISCONNECTED;
318                 break;
319
320                 case CONNECTED:
321                 case DISCONNECTING:
322                     if ( mCT.mState != PhoneConstants.State.IDLE
323                             && !mSST.isConcurrentVoiceAndDataAllowed()) {
324                         ret = PhoneConstants.DataState.SUSPENDED;
325                     } else {
326                         ret = PhoneConstants.DataState.CONNECTED;
327                     }
328                 break;
329
330                 case CONNECTING:
331                 case SCANNING:
332                     ret = PhoneConstants.DataState.CONNECTING;
333                 break;
334             }
335         }
336
337         return ret;
338     }
339
340     @Override
341     public DataActivityState getDataActivityState() {
342         DataActivityState ret = DataActivityState.NONE;
343
344         if (mSST.getCurrentDataConnectionState() == ServiceState.STATE_IN_SERVICE) {
345             switch (mDcTracker.getActivity()) {
346                 case DATAIN:
347                     ret = DataActivityState.DATAIN;
348                 break;
349
350                 case DATAOUT:
351                     ret = DataActivityState.DATAOUT;
352                 break;
353
354                 case DATAINANDOUT:
355                     ret = DataActivityState.DATAINANDOUT;
356                 break;
357
358                 case DORMANT:
359                     ret = DataActivityState.DORMANT;
360                 break;
361
362                 default:
363                     ret = DataActivityState.NONE;
364                 break;
365             }
366         }
367
368         return ret;
369     }
370
371     /**
372      * Notify any interested party of a Phone state change
373      * {@link com.android.internal.telephony.PhoneConstants.State}
374      */
375     /*package*/ void notifyPhoneStateChanged() {
376         mNotifier.notifyPhoneState(this);
377     }
378
379     /**
380      * Notify registrants of a change in the call state. This notifies changes in
381      * {@link com.android.internal.telephony.Call.State}. Use this when changes
382      * in the precise call state are needed, else use notifyPhoneStateChanged.
383      */
384     /*package*/ void notifyPreciseCallStateChanged() {
385         /* we'd love it if this was package-scoped*/
386         super.notifyPreciseCallStateChangedP();
387     }
388
389     /*package*/ void
390     notifyNewRingingConnection(Connection c) {
391         /* we'd love it if this was package-scoped*/
392         super.notifyNewRingingConnectionP(c);
393     }
394
395     /*package*/ void
396     notifyDisconnect(Connection cn) {
397         mDisconnectRegistrants.notifyResult(cn);
398     }
399
400     void notifyUnknownConnection() {
401         mUnknownConnectionRegistrants.notifyResult(this);
402     }
403
404     void notifySuppServiceFailed(SuppService code) {
405         mSuppServiceFailedRegistrants.notifyResult(code);
406     }
407
408     /*package*/ void
409     notifyServiceStateChanged(ServiceState ss) {
410         super.notifyServiceStateChangedP(ss);
411     }
412
413     /*package*/
414     void notifyLocationChanged() {
415         mNotifier.notifyCellLocation(this);
416     }
417
418     @Override
419     public void
420     notifyCallForwardingIndicator() {
421         mNotifier.notifyCallForwardingChanged(this);
422     }
423
424     // override for allowing access from other classes of this package
425     /**
426      * {@inheritDoc}
427      */
428     @Override
429     public final void
430     setSystemProperty(String property, String value) {
431         super.setSystemProperty(property, value);
432     }
433
434     @Override
435     public void registerForSuppServiceNotification(
436             Handler h, int what, Object obj) {
437         mSsnRegistrants.addUnique(h, what, obj);
438         if (mSsnRegistrants.size() == 1) mCi.setSuppServiceNotifications(true, null);
439     }
440
441     @Override
442     public void unregisterForSuppServiceNotification(Handler h) {
443         mSsnRegistrants.remove(h);
444         if (mSsnRegistrants.size() == 0) mCi.setSuppServiceNotifications(false, null);
445     }
446
447     @Override
448     public void
449     acceptCall() throws CallStateException {
450         mCT.acceptCall();
451     }
452
453     @Override
454     public void
455     rejectCall() throws CallStateException {
456         mCT.rejectCall();
457     }
458
459     @Override
460     public void
461     switchHoldingAndActive() throws CallStateException {
462         mCT.switchWaitingOrHoldingAndActive();
463     }
464
465     @Override
466     public boolean canConference() {
467         return mCT.canConference();
468     }
469
470     public boolean canDial() {
471         return mCT.canDial();
472     }
473
474     @Override
475     public void conference() {
476         mCT.conference();
477     }
478
479     @Override
480     public void clearDisconnected() {
481         mCT.clearDisconnected();
482     }
483
484     @Override
485     public boolean canTransfer() {
486         return mCT.canTransfer();
487     }
488
489     @Override
490     public void explicitCallTransfer() {
491         mCT.explicitCallTransfer();
492     }
493
494     @Override
495     public GsmCall
496     getForegroundCall() {
497         return mCT.mForegroundCall;
498     }
499
500     @Override
501     public GsmCall
502     getBackgroundCall() {
503         return mCT.mBackgroundCall;
504     }
505
506     @Override
507     public GsmCall
508     getRingingCall() {
509         return mCT.mRingingCall;
510     }
511
512     private boolean handleCallDeflectionIncallSupplementaryService(
513             String dialString) {
514         if (dialString.length() > 1) {
515             return false;
516         }
517
518         if (getRingingCall().getState() != GsmCall.State.IDLE) {
519             if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 0: rejectCall");
520             try {
521                 mCT.rejectCall();
522             } catch (CallStateException e) {
523                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
524                     "reject failed", e);
525                 notifySuppServiceFailed(Phone.SuppService.REJECT);
526             }
527         } else if (getBackgroundCall().getState() != GsmCall.State.IDLE) {
528             if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
529                     "MmiCode 0: hangupWaitingOrBackground");
530             mCT.hangupWaitingOrBackground();
531         }
532
533         return true;
534     }
535
536     private boolean handleCallWaitingIncallSupplementaryService(
537             String dialString) {
538         int len = dialString.length();
539
540         if (len > 2) {
541             return false;
542         }
543
544         GsmCall call = getForegroundCall();
545
546         try {
547             if (len > 1) {
548                 char ch = dialString.charAt(1);
549                 int callIndex = ch - '0';
550
551                 if (callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) {
552                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
553                             "MmiCode 1: hangupConnectionByIndex " +
554                             callIndex);
555                     mCT.hangupConnectionByIndex(call, callIndex);
556                 }
557             } else {
558                 if (call.getState() != GsmCall.State.IDLE) {
559                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
560                             "MmiCode 1: hangup foreground");
561                     //mCT.hangupForegroundResumeBackground();
562                     mCT.hangup(call);
563                 } else {
564                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
565                             "MmiCode 1: switchWaitingOrHoldingAndActive");
566                     mCT.switchWaitingOrHoldingAndActive();
567                 }
568             }
569         } catch (CallStateException e) {
570             if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
571                 "hangup failed", e);
572             notifySuppServiceFailed(Phone.SuppService.HANGUP);
573         }
574
575         return true;
576     }
577
578     private boolean handleCallHoldIncallSupplementaryService(String dialString) {
579         int len = dialString.length();
580
581         if (len > 2) {
582             return false;
583         }
584
585         GsmCall call = getForegroundCall();
586
587         if (len > 1) {
588             try {
589                 char ch = dialString.charAt(1);
590                 int callIndex = ch - '0';
591                 GsmConnection conn = mCT.getConnectionByIndex(call, callIndex);
592
593                 // gsm index starts at 1, up to 5 connections in a call,
594                 if (conn != null && callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) {
595                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 2: separate call "+
596                             callIndex);
597                     mCT.separate(conn);
598                 } else {
599                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "separate: invalid call index "+
600                             callIndex);
601                     notifySuppServiceFailed(Phone.SuppService.SEPARATE);
602                 }
603             } catch (CallStateException e) {
604                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
605                     "separate failed", e);
606                 notifySuppServiceFailed(Phone.SuppService.SEPARATE);
607             }
608         } else {
609             try {
610                 if (getRingingCall().getState() != GsmCall.State.IDLE) {
611                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
612                     "MmiCode 2: accept ringing call");
613                     mCT.acceptCall();
614                 } else {
615                     if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
616                     "MmiCode 2: switchWaitingOrHoldingAndActive");
617                     mCT.switchWaitingOrHoldingAndActive();
618                 }
619             } catch (CallStateException e) {
620                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
621                     "switch failed", e);
622                 notifySuppServiceFailed(Phone.SuppService.SWITCH);
623             }
624         }
625
626         return true;
627     }
628
629     private boolean handleMultipartyIncallSupplementaryService(
630             String dialString) {
631         if (dialString.length() > 1) {
632             return false;
633         }
634
635         if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 3: merge calls");
636         conference();
637         return true;
638     }
639
640     private boolean handleEctIncallSupplementaryService(String dialString) {
641
642         int len = dialString.length();
643
644         if (len != 1) {
645             return false;
646         }
647
648         if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "MmiCode 4: explicit call transfer");
649         explicitCallTransfer();
650         return true;
651     }
652
653     private boolean handleCcbsIncallSupplementaryService(String dialString) {
654         if (dialString.length() > 1) {
655             return false;
656         }
657
658         Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!");
659         // Treat it as an "unknown" service.
660         notifySuppServiceFailed(Phone.SuppService.UNKNOWN);
661         return true;
662     }
663
664     @Override
665     public boolean handleInCallMmiCommands(String dialString) {
666         if (!isInCall()) {
667             return false;
668         }
669
670         if (TextUtils.isEmpty(dialString)) {
671             return false;
672         }
673
674         boolean result = false;
675         char ch = dialString.charAt(0);
676         switch (ch) {
677             case '0':
678                 result = handleCallDeflectionIncallSupplementaryService(
679                         dialString);
680                 break;
681             case '1':
682                 result = handleCallWaitingIncallSupplementaryService(
683                         dialString);
684                 break;
685             case '2':
686                 result = handleCallHoldIncallSupplementaryService(dialString);
687                 break;
688             case '3':
689                 result = handleMultipartyIncallSupplementaryService(dialString);
690                 break;
691             case '4':
692                 result = handleEctIncallSupplementaryService(dialString);
693                 break;
694             case '5':
695                 result = handleCcbsIncallSupplementaryService(dialString);
696                 break;
697             default:
698                 break;
699         }
700
701         return result;
702     }
703
704     boolean isInCall() {
705         GsmCall.State foregroundCallState = getForegroundCall().getState();
706         GsmCall.State backgroundCallState = getBackgroundCall().getState();
707         GsmCall.State ringingCallState = getRingingCall().getState();
708
709        return (foregroundCallState.isAlive() ||
710                 backgroundCallState.isAlive() ||
711                 ringingCallState.isAlive());
712     }
713
714     @Override
715     public Connection
716     dial(String dialString) throws CallStateException {
717         return dial(dialString, null);
718     }
719
720     @Override
721     public Connection
722     dial (String dialString, UUSInfo uusInfo) throws CallStateException {
723         // Need to make sure dialString gets parsed properly
724         String newDialString = PhoneNumberUtils.stripSeparators(dialString);
725
726         // handle in-call MMI first if applicable
727         if (handleInCallMmiCommands(newDialString)) {
728             return null;
729         }
730
731         // Only look at the Network portion for mmi
732         String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
733         GsmMmiCode mmi =
734                 GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
735         if (LOCAL_DEBUG) Rlog.d(LOG_TAG,
736                                "dialing w/ mmi '" + mmi + "'...");
737
738         if (mmi == null) {
739             return mCT.dial(newDialString, uusInfo);
740         } else if (mmi.isTemporaryModeCLIR()) {
741             return mCT.dial(mmi.mDialingNumber, mmi.getCLIRMode(), uusInfo);
742         } else {
743             mPendingMMIs.add(mmi);
744             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
745             mmi.processCode();
746
747             // FIXME should this return null or something else?
748             return null;
749         }
750     }
751
752     @Override
753     public boolean handlePinMmi(String dialString) {
754         GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this, mUiccApplication.get());
755
756         if (mmi != null && mmi.isPinCommand()) {
757             mPendingMMIs.add(mmi);
758             mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
759             mmi.processCode();
760             return true;
761         }
762
763         return false;
764     }
765
766     @Override
767     public void sendUssdResponse(String ussdMessge) {
768         GsmMmiCode mmi = GsmMmiCode.newFromUssdUserInput(ussdMessge, this, mUiccApplication.get());
769         mPendingMMIs.add(mmi);
770         mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
771         mmi.sendUssd(ussdMessge);
772     }
773
774     @Override
775     public void
776     sendDtmf(char c) {
777         if (!PhoneNumberUtils.is12Key(c)) {
778             Rlog.e(LOG_TAG,
779                     "sendDtmf called with invalid character '" + c + "'");
780         } else {
781             if (mCT.mState ==  PhoneConstants.State.OFFHOOK) {
782                 mCi.sendDtmf(c, null);
783             }
784         }
785     }
786
787     @Override
788     public void
789     startDtmf(char c) {
790         if (!PhoneNumberUtils.is12Key(c)) {
791             Rlog.e(LOG_TAG,
792                 "startDtmf called with invalid character '" + c + "'");
793         } else {
794             mCi.startDtmf(c, null);
795         }
796     }
797
798     @Override
799     public void
800     stopDtmf() {
801         mCi.stopDtmf(null);
802     }
803
804     public void
805     sendBurstDtmf(String dtmfString) {
806         Rlog.e(LOG_TAG, "[GSMPhone] sendBurstDtmf() is a CDMA method");
807     }
808
809     @Override
810     public void
811     setRadioPower(boolean power) {
812         mSST.setRadioPower(power);
813     }
814
815     private void storeVoiceMailNumber(String number) {
816         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
817         SharedPreferences.Editor editor = sp.edit();
818         editor.putString(VM_NUMBER, number);
819         editor.apply();
820         setVmSimImsi(getSubscriberId());
821     }
822
823     @Override
824     public String getVoiceMailNumber() {
825         // Read from the SIM. If its null, try reading from the shared preference area.
826         IccRecords r = mIccRecords.get();
827         String number = (r != null) ? r.getVoiceMailNumber() : "";
828         if (TextUtils.isEmpty(number)) {
829             SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
830             number = sp.getString(VM_NUMBER, null);
831         }
832         return number;
833     }
834
835     private String getVmSimImsi() {
836         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
837         return sp.getString(VM_SIM_IMSI, null);
838     }
839
840     private void setVmSimImsi(String imsi) {
841         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
842         SharedPreferences.Editor editor = sp.edit();
843         editor.putString(VM_SIM_IMSI, imsi);
844         editor.apply();
845     }
846
847     @Override
848     public String getVoiceMailAlphaTag() {
849         String ret;
850         IccRecords r = mIccRecords.get();
851
852         ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
853
854         if (ret == null || ret.length() == 0) {
855             return mContext.getText(
856                 com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
857         }
858
859         return ret;
860     }
861
862     @Override
863     public String getDeviceId() {
864         return mImei;
865     }
866
867     @Override
868     public String getDeviceSvn() {
869         return mImeiSv;
870     }
871
872     @Override
873     public String getImei() {
874         return mImei;
875     }
876
877     @Override
878     public String getEsn() {
879         Rlog.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method");
880         return "0";
881     }
882
883     @Override
884     public String getMeid() {
885         Rlog.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method");
886         return "0";
887     }
888
889     @Override
890     public String getSubscriberId() {
891         IccRecords r = mIccRecords.get();
892         return (r != null) ? r.getIMSI() : null;
893     }
894
895     @Override
896     public String getGroupIdLevel1() {
897         IccRecords r = mIccRecords.get();
898         return (r != null) ? r.getGid1() : null;
899     }
900
901     @Override
902     public String getLine1Number() {
903         IccRecords r = mIccRecords.get();
904         return (r != null) ? r.getMsisdnNumber() : null;
905     }
906
907     @Override
908     public String getMsisdn() {
909         IccRecords r = mIccRecords.get();
910         return (r != null) ? r.getMsisdnNumber() : null;
911     }
912
913     @Override
914     public String getLine1AlphaTag() {
915         IccRecords r = mIccRecords.get();
916         return (r != null) ? r.getMsisdnAlphaTag() : null;
917     }
918
919     @Override
920     public void setLine1Number(String alphaTag, String number, Message onComplete) {
921         IccRecords r = mIccRecords.get();
922         if (r != null) {
923             r.setMsisdnNumber(alphaTag, number, onComplete);
924         }
925     }
926
927     @Override
928     public void setVoiceMailNumber(String alphaTag,
929                             String voiceMailNumber,
930                             Message onComplete) {
931
932         Message resp;
933         mVmNumber = voiceMailNumber;
934         resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
935         IccRecords r = mIccRecords.get();
936         if (r != null) {
937             r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
938         }
939     }
940
941     private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
942         switch (commandInterfaceCFReason) {
943         case CF_REASON_UNCONDITIONAL:
944         case CF_REASON_BUSY:
945         case CF_REASON_NO_REPLY:
946         case CF_REASON_NOT_REACHABLE:
947         case CF_REASON_ALL:
948         case CF_REASON_ALL_CONDITIONAL:
949             return true;
950         default:
951             return false;
952         }
953     }
954
955     private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
956         switch (commandInterfaceCFAction) {
957         case CF_ACTION_DISABLE:
958         case CF_ACTION_ENABLE:
959         case CF_ACTION_REGISTRATION:
960         case CF_ACTION_ERASURE:
961             return true;
962         default:
963             return false;
964         }
965     }
966
967     protected  boolean isCfEnable(int action) {
968         return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
969     }
970
971     @Override
972     public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
973         if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
974             if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "requesting call forwarding query.");
975             Message resp;
976             if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
977                 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
978             } else {
979                 resp = onComplete;
980             }
981             mCi.queryCallForwardStatus(commandInterfaceCFReason,0,null,resp);
982         }
983     }
984
985     @Override
986     public void setCallForwardingOption(int commandInterfaceCFAction,
987             int commandInterfaceCFReason,
988             String dialingNumber,
989             int timerSeconds,
990             Message onComplete) {
991         if (    (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
992                 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
993
994             Message resp;
995             if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
996                 Cfu cfu = new Cfu(dialingNumber, onComplete);
997                 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
998                         isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
999             } else {
1000                 resp = onComplete;
1001             }
1002             mCi.setCallForward(commandInterfaceCFAction,
1003                     commandInterfaceCFReason,
1004                     CommandsInterface.SERVICE_CLASS_VOICE,
1005                     dialingNumber,
1006                     timerSeconds,
1007                     resp);
1008         }
1009     }
1010
1011     @Override
1012     public void getOutgoingCallerIdDisplay(Message onComplete) {
1013         mCi.getCLIR(onComplete);
1014     }
1015
1016     @Override
1017     public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
1018                                            Message onComplete) {
1019         mCi.setCLIR(commandInterfaceCLIRMode,
1020                 obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
1021     }
1022
1023     @Override
1024     public void getCallWaiting(Message onComplete) {
1025         //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
1026         //class parameter in call waiting interrogation  to network
1027         mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
1028     }
1029
1030     @Override
1031     public void setCallWaiting(boolean enable, Message onComplete) {
1032         mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1033     }
1034
1035     @Override
1036     public void
1037     getAvailableNetworks(Message response) {
1038         mCi.getAvailableNetworks(response);
1039     }
1040
1041     /**
1042      * Small container class used to hold information relevant to
1043      * the carrier selection process. operatorNumeric can be ""
1044      * if we are looking for automatic selection. operatorAlphaLong is the
1045      * corresponding operator name.
1046      */
1047     private static class NetworkSelectMessage {
1048         public Message message;
1049         public String operatorNumeric;
1050         public String operatorAlphaLong;
1051     }
1052
1053     @Override
1054     public void
1055     setNetworkSelectionModeAutomatic(Message response) {
1056         // wrap the response message in our own message along with
1057         // an empty string (to indicate automatic selection) for the
1058         // operator's id.
1059         NetworkSelectMessage nsm = new NetworkSelectMessage();
1060         nsm.message = response;
1061         nsm.operatorNumeric = "";
1062         nsm.operatorAlphaLong = "";
1063
1064         // get the message
1065         Message msg = obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
1066         if (LOCAL_DEBUG)
1067             Rlog.d(LOG_TAG, "wrapping and sending message to connect automatically");
1068
1069         mCi.setNetworkSelectionModeAutomatic(msg);
1070     }
1071
1072     @Override
1073     public void
1074     selectNetworkManually(OperatorInfo network,
1075             Message response) {
1076         // wrap the response message in our own message along with
1077         // the operator's id.
1078         NetworkSelectMessage nsm = new NetworkSelectMessage();
1079         nsm.message = response;
1080         nsm.operatorNumeric = network.getOperatorNumeric();
1081         nsm.operatorAlphaLong = network.getOperatorAlphaLong();
1082
1083         // get the message
1084         Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
1085
1086         mCi.setNetworkSelectionModeManual(network.getOperatorNumeric(), msg);
1087     }
1088
1089     @Override
1090     public void
1091     getNeighboringCids(Message response) {
1092         mCi.getNeighboringCids(response);
1093     }
1094
1095     @Override
1096     public void setOnPostDialCharacter(Handler h, int what, Object obj) {
1097         mPostDialHandler = new Registrant(h, what, obj);
1098     }
1099
1100     @Override
1101     public void setMute(boolean muted) {
1102         mCT.setMute(muted);
1103     }
1104
1105     @Override
1106     public boolean getMute() {
1107         return mCT.getMute();
1108     }
1109
1110     @Override
1111     public void getDataCallList(Message response) {
1112         mCi.getDataCallList(response);
1113     }
1114
1115     @Override
1116     public void updateServiceLocation() {
1117         mSST.enableSingleLocationUpdate();
1118     }
1119
1120     @Override
1121     public void enableLocationUpdates() {
1122         mSST.enableLocationUpdates();
1123     }
1124
1125     @Override
1126     public void disableLocationUpdates() {
1127         mSST.disableLocationUpdates();
1128     }
1129
1130     @Override
1131     public boolean getDataRoamingEnabled() {
1132         return mDcTracker.getDataOnRoamingEnabled();
1133     }
1134
1135     @Override
1136     public void setDataRoamingEnabled(boolean enable) {
1137         mDcTracker.setDataOnRoamingEnabled(enable);
1138     }
1139
1140     /**
1141      * Removes the given MMI from the pending list and notifies
1142      * registrants that it is complete.
1143      * @param mmi MMI that is done
1144      */
1145     /*package*/ void
1146     onMMIDone(GsmMmiCode mmi) {
1147         /* Only notify complete if it's on the pending list.
1148          * Otherwise, it's already been handled (eg, previously canceled).
1149          * The exception is cancellation of an incoming USSD-REQUEST, which is
1150          * not on the list.
1151          */
1152         if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) {
1153             mMmiCompleteRegistrants.notifyRegistrants(
1154                 new AsyncResult(null, mmi, null));
1155         }
1156     }
1157
1158
1159     private void
1160     onNetworkInitiatedUssd(GsmMmiCode mmi) {
1161         mMmiCompleteRegistrants.notifyRegistrants(
1162             new AsyncResult(null, mmi, null));
1163     }
1164
1165
1166     /** ussdMode is one of CommandsInterface.USSD_MODE_* */
1167     private void
1168     onIncomingUSSD (int ussdMode, String ussdMessage) {
1169         boolean isUssdError;
1170         boolean isUssdRequest;
1171
1172         isUssdRequest
1173             = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
1174
1175         isUssdError
1176             = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
1177                 && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
1178
1179         // See comments in GsmMmiCode.java
1180         // USSD requests aren't finished until one
1181         // of these two events happen
1182         GsmMmiCode found = null;
1183         for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
1184             if(mPendingMMIs.get(i).isPendingUSSD()) {
1185                 found = mPendingMMIs.get(i);
1186                 break;
1187             }
1188         }
1189
1190         if (found != null) {
1191             // Complete pending USSD
1192
1193             if (isUssdError) {
1194                 found.onUssdFinishedError();
1195             } else {
1196                 found.onUssdFinished(ussdMessage, isUssdRequest);
1197             }
1198         } else { // pending USSD not found
1199             // The network may initiate its own USSD request
1200
1201             // ignore everything that isnt a Notify or a Request
1202             // also, discard if there is no message to present
1203             if (!isUssdError && ussdMessage != null) {
1204                 GsmMmiCode mmi;
1205                 mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
1206                                                    isUssdRequest,
1207                                                    GSMPhone.this,
1208                                                    mUiccApplication.get());
1209                 onNetworkInitiatedUssd(mmi);
1210             }
1211         }
1212     }
1213
1214     /**
1215      * Make sure the network knows our preferred setting.
1216      */
1217     protected  void syncClirSetting() {
1218         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1219         int clirSetting = sp.getInt(CLIR_KEY, -1);
1220         if (clirSetting >= 0) {
1221             mCi.setCLIR(clirSetting, null);
1222         }
1223     }
1224
1225     @Override
1226     public void handleMessage (Message msg) {
1227         AsyncResult ar;
1228         Message onComplete;
1229
1230         if (!mIsTheCurrentActivePhone) {
1231             Rlog.e(LOG_TAG, "Received message " + msg +
1232                     "[" + msg.what + "] while being destroyed. Ignoring.");
1233             return;
1234         }
1235         switch (msg.what) {
1236             case EVENT_RADIO_AVAILABLE: {
1237                 mCi.getBasebandVersion(
1238                         obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
1239
1240                 mCi.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
1241                 mCi.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
1242             }
1243             break;
1244
1245             case EVENT_RADIO_ON:
1246             break;
1247
1248             case EVENT_REGISTERED_TO_NETWORK:
1249                 syncClirSetting();
1250                 break;
1251
1252             case EVENT_SIM_RECORDS_LOADED:
1253                 updateCurrentCarrierInProvider();
1254
1255                 // Check if this is a different SIM than the previous one. If so unset the
1256                 // voice mail number.
1257                 String imsi = getVmSimImsi();
1258                 String imsiFromSIM = getSubscriberId();
1259                 if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
1260                     storeVoiceMailNumber(null);
1261                     setVmSimImsi(null);
1262                 }
1263
1264             break;
1265
1266             case EVENT_GET_BASEBAND_VERSION_DONE:
1267                 ar = (AsyncResult)msg.obj;
1268
1269                 if (ar.exception != null) {
1270                     break;
1271                 }
1272
1273                 if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Baseband version: " + ar.result);
1274                 setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result);
1275             break;
1276
1277             case EVENT_GET_IMEI_DONE:
1278                 ar = (AsyncResult)msg.obj;
1279
1280                 if (ar.exception != null) {
1281                     break;
1282                 }
1283
1284                 mImei = (String)ar.result;
1285             break;
1286
1287             case EVENT_GET_IMEISV_DONE:
1288                 ar = (AsyncResult)msg.obj;
1289
1290                 if (ar.exception != null) {
1291                     break;
1292                 }
1293
1294                 mImeiSv = (String)ar.result;
1295             break;
1296
1297             case EVENT_USSD:
1298                 ar = (AsyncResult)msg.obj;
1299
1300                 String[] ussdResult = (String[]) ar.result;
1301
1302                 if (ussdResult.length > 1) {
1303                     try {
1304                         onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
1305                     } catch (NumberFormatException e) {
1306                         Rlog.w(LOG_TAG, "error parsing USSD");
1307                     }
1308                 }
1309             break;
1310
1311             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
1312                 // Some MMI requests (eg USSD) are not completed
1313                 // within the course of a CommandsInterface request
1314                 // If the radio shuts off or resets while one of these
1315                 // is pending, we need to clean up.
1316
1317                 for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
1318                     if (mPendingMMIs.get(i).isPendingUSSD()) {
1319                         mPendingMMIs.get(i).onUssdFinishedError();
1320                     }
1321                 }
1322             break;
1323
1324             case EVENT_SSN:
1325                 ar = (AsyncResult)msg.obj;
1326                 SuppServiceNotification not = (SuppServiceNotification) ar.result;
1327                 mSsnRegistrants.notifyRegistrants(ar);
1328             break;
1329
1330             case EVENT_SET_CALL_FORWARD_DONE:
1331                 ar = (AsyncResult)msg.obj;
1332                 IccRecords r = mIccRecords.get();
1333                 Cfu cfu = (Cfu) ar.userObj;
1334                 if (ar.exception == null && r != null) {
1335                     r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
1336                 }
1337                 if (cfu.mOnComplete != null) {
1338                     AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
1339                     cfu.mOnComplete.sendToTarget();
1340                 }
1341                 break;
1342
1343             case EVENT_SET_VM_NUMBER_DONE:
1344                 ar = (AsyncResult)msg.obj;
1345                 if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
1346                     storeVoiceMailNumber(mVmNumber);
1347                     ar.exception = null;
1348                 }
1349                 onComplete = (Message) ar.userObj;
1350                 if (onComplete != null) {
1351                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1352                     onComplete.sendToTarget();
1353                 }
1354                 break;
1355
1356
1357             case EVENT_GET_CALL_FORWARD_DONE:
1358                 ar = (AsyncResult)msg.obj;
1359                 if (ar.exception == null) {
1360                     handleCfuQueryResult((CallForwardInfo[])ar.result);
1361                 }
1362                 onComplete = (Message) ar.userObj;
1363                 if (onComplete != null) {
1364                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1365                     onComplete.sendToTarget();
1366                 }
1367                 break;
1368
1369             case EVENT_SET_NETWORK_AUTOMATIC:
1370                 ar = (AsyncResult)msg.obj;
1371                 setNetworkSelectionModeAutomatic((Message)ar.result);
1372                 break;
1373
1374             case EVENT_ICC_RECORD_EVENTS:
1375                 ar = (AsyncResult)msg.obj;
1376                 processIccRecordEvents((Integer)ar.result);
1377                 break;
1378
1379             // handle the select network completion callbacks.
1380             case EVENT_SET_NETWORK_MANUAL_COMPLETE:
1381             case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
1382                 handleSetSelectNetwork((AsyncResult) msg.obj);
1383                 break;
1384
1385             case EVENT_SET_CLIR_COMPLETE:
1386                 ar = (AsyncResult)msg.obj;
1387                 if (ar.exception == null) {
1388                     saveClirSetting(msg.arg1);
1389                 }
1390                 onComplete = (Message) ar.userObj;
1391                 if (onComplete != null) {
1392                     AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1393                     onComplete.sendToTarget();
1394                 }
1395                 break;
1396
1397              default:
1398                  super.handleMessage(msg);
1399         }
1400     }
1401
1402     @Override
1403     protected void onUpdateIccAvailability() {
1404         if (mUiccController == null ) {
1405             return;
1406         }
1407
1408         UiccCardApplication newUiccApplication =
1409                 mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);
1410
1411         UiccCardApplication app = mUiccApplication.get();
1412         if (app != newUiccApplication) {
1413             if (app != null) {
1414                 if (LOCAL_DEBUG) log("Removing stale icc objects.");
1415                 if (mIccRecords.get() != null) {
1416                     unregisterForSimRecordEvents();
1417                     mSimPhoneBookIntManager.updateIccRecords(null);
1418                 }
1419                 mIccRecords.set(null);
1420                 mUiccApplication.set(null);
1421             }
1422             if (newUiccApplication != null) {
1423                 if (LOCAL_DEBUG) log("New Uicc application found");
1424                 mUiccApplication.set(newUiccApplication);
1425                 mIccRecords.set(newUiccApplication.getIccRecords());
1426                 registerForSimRecordEvents();
1427                 mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get());
1428             }
1429         }
1430     }
1431
1432     private void processIccRecordEvents(int eventCode) {
1433         switch (eventCode) {
1434             case IccRecords.EVENT_CFI:
1435                 notifyCallForwardingIndicator();
1436                 break;
1437             case IccRecords.EVENT_MWI:
1438                 notifyMessageWaitingIndicator();
1439                 break;
1440         }
1441     }
1442
1443    /**
1444      * Sets the "current" field in the telephony provider according to the SIM's operator
1445      *
1446      * @return true for success; false otherwise.
1447      */
1448     public boolean updateCurrentCarrierInProvider() {
1449         IccRecords r = mIccRecords.get();
1450         if (r != null) {
1451             try {
1452                 Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
1453                 ContentValues map = new ContentValues();
1454                 map.put(Telephony.Carriers.NUMERIC, r.getOperatorNumeric());
1455                 mContext.getContentResolver().insert(uri, map);
1456                 return true;
1457             } catch (SQLException e) {
1458                 Rlog.e(LOG_TAG, "Can't store current operator", e);
1459             }
1460         }
1461         return false;
1462     }
1463
1464     /**
1465      * Used to track the settings upon completion of the network change.
1466      */
1467     private void handleSetSelectNetwork(AsyncResult ar) {
1468         // look for our wrapper within the asyncresult, skip the rest if it
1469         // is null.
1470         if (!(ar.userObj instanceof NetworkSelectMessage)) {
1471             if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "unexpected result from user object.");
1472             return;
1473         }
1474
1475         NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj;
1476
1477         // found the object, now we send off the message we had originally
1478         // attached to the request.
1479         if (nsm.message != null) {
1480             if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "sending original message to recipient");
1481             AsyncResult.forMessage(nsm.message, ar.result, ar.exception);
1482             nsm.message.sendToTarget();
1483         }
1484
1485         // open the shared preferences editor, and write the value.
1486         // nsm.operatorNumeric is "" if we're in automatic.selection.
1487         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1488         SharedPreferences.Editor editor = sp.edit();
1489         editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric);
1490         editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong);
1491
1492         // commit and log the result.
1493         if (! editor.commit()) {
1494             Rlog.e(LOG_TAG, "failed to commit network selection preference");
1495         }
1496
1497     }
1498
1499     /**
1500      * Saves CLIR setting so that we can re-apply it as necessary
1501      * (in case the RIL resets it across reboots).
1502      */
1503     public void saveClirSetting(int commandInterfaceCLIRMode) {
1504         // open the shared preferences editor, and write the value.
1505         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1506         SharedPreferences.Editor editor = sp.edit();
1507         editor.putInt(CLIR_KEY, commandInterfaceCLIRMode);
1508
1509         // commit and log the result.
1510         if (! editor.commit()) {
1511             Rlog.e(LOG_TAG, "failed to commit CLIR preference");
1512         }
1513     }
1514
1515     private void handleCfuQueryResult(CallForwardInfo[] infos) {
1516         IccRecords r = mIccRecords.get();
1517         if (r != null) {
1518             if (infos == null || infos.length == 0) {
1519                 // Assume the default is not active
1520                 // Set unconditional CFF in SIM to false
1521                 r.setVoiceCallForwardingFlag(1, false, null);
1522             } else {
1523                 for (int i = 0, s = infos.length; i < s; i++) {
1524                     if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
1525                         r.setVoiceCallForwardingFlag(1, (infos[i].status == 1),
1526                             infos[i].number);
1527                         // should only have the one
1528                         break;
1529                     }
1530                 }
1531             }
1532         }
1533     }
1534
1535     /**
1536      * Retrieves the PhoneSubInfo of the GSMPhone
1537      */
1538     @Override
1539     public PhoneSubInfo getPhoneSubInfo(){
1540         return mSubInfo;
1541     }
1542
1543     /**
1544      * Retrieves the IccPhoneBookInterfaceManager of the GSMPhone
1545      */
1546     @Override
1547     public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
1548         return mSimPhoneBookIntManager;
1549     }
1550
1551     /**
1552      * Activate or deactivate cell broadcast SMS.
1553      *
1554      * @param activate 0 = activate, 1 = deactivate
1555      * @param response Callback message is empty on completion
1556      */
1557     @Override
1558     public void activateCellBroadcastSms(int activate, Message response) {
1559         Rlog.e(LOG_TAG, "[GSMPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
1560         response.sendToTarget();
1561     }
1562
1563     /**
1564      * Query the current configuration of cdma cell broadcast SMS.
1565      *
1566      * @param response Callback message is empty on completion
1567      */
1568     @Override
1569     public void getCellBroadcastSmsConfig(Message response) {
1570         Rlog.e(LOG_TAG, "[GSMPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
1571         response.sendToTarget();
1572     }
1573
1574     /**
1575      * Configure cdma cell broadcast SMS.
1576      *
1577      * @param response Callback message is empty on completion
1578      */
1579     @Override
1580     public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
1581         Rlog.e(LOG_TAG, "[GSMPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
1582         response.sendToTarget();
1583     }
1584
1585     @Override
1586     public boolean isCspPlmnEnabled() {
1587         IccRecords r = mIccRecords.get();
1588         return (r != null) ? r.isCspPlmnEnabled() : false;
1589     }
1590
1591     private void registerForSimRecordEvents() {
1592         IccRecords r = mIccRecords.get();
1593         if (r == null) {
1594             return;
1595         }
1596         r.registerForNetworkSelectionModeAutomatic(
1597                 this, EVENT_SET_NETWORK_AUTOMATIC, null);
1598         r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
1599         r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
1600     }
1601
1602     private void unregisterForSimRecordEvents() {
1603         IccRecords r = mIccRecords.get();
1604         if (r == null) {
1605             return;
1606         }
1607         r.unregisterForNetworkSelectionModeAutomatic(this);
1608         r.unregisterForRecordsEvents(this);
1609         r.unregisterForRecordsLoaded(this);
1610     }
1611
1612     @Override
1613     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1614         pw.println("GSMPhone extends:");
1615         super.dump(fd, pw, args);
1616         pw.println(" mCT=" + mCT);
1617         pw.println(" mSST=" + mSST);
1618         pw.println(" mPendingMMIs=" + mPendingMMIs);
1619         pw.println(" mSimPhoneBookIntManager=" + mSimPhoneBookIntManager);
1620         pw.println(" mSubInfo=" + mSubInfo);
1621         if (VDBG) pw.println(" mImei=" + mImei);
1622         if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
1623         pw.println(" mVmNumber=" + mVmNumber);
1624     }
1625
1626     protected void log(String s) {
1627         Rlog.d(LOG_TAG, "[GSMPhone] " + s);
1628     }
1629 }