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