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