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