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