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