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