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