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