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