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