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