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