GSMPhone.java revision 4fe735103bd4d8026a25f4b0b40784fe60cddac4
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
956        if (TextUtils.isEmpty(number)) {
957            String[] listArray = getContext().getResources()
958                .getStringArray(com.android.internal.R.array.config_default_vm_number);
959            if (listArray != null && listArray.length > 0) {
960                for (int i=0; i<listArray.length; i++) {
961                    if (!TextUtils.isEmpty(listArray[i])) {
962                        String[] defaultVMNumberArray = listArray[i].split(";");
963                        if (defaultVMNumberArray != null && defaultVMNumberArray.length > 0) {
964                            if (defaultVMNumberArray.length == 1) {
965                                number = defaultVMNumberArray[0];
966                            } else if (defaultVMNumberArray.length == 2 &&
967                                    !TextUtils.isEmpty(defaultVMNumberArray[1]) &&
968                                    defaultVMNumberArray[1].equalsIgnoreCase(getGroupIdLevel1())) {
969                                number = defaultVMNumberArray[0];
970                                break;
971                            }
972                        }
973                    }
974                }
975            }
976        }
977        return number;
978    }
979
980    private String getVmSimImsi() {
981        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
982        return sp.getString(VM_SIM_IMSI + getPhoneId(), null);
983    }
984
985    private void setVmSimImsi(String imsi) {
986        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
987        SharedPreferences.Editor editor = sp.edit();
988        editor.putString(VM_SIM_IMSI + getPhoneId(), imsi);
989        editor.apply();
990    }
991
992    @Override
993    public String getVoiceMailAlphaTag() {
994        String ret;
995        IccRecords r = mIccRecords.get();
996
997        ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
998
999        if (ret == null || ret.length() == 0) {
1000            return mContext.getText(
1001                com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
1002        }
1003
1004        return ret;
1005    }
1006
1007    @Override
1008    public String getDeviceId() {
1009        return mImei;
1010    }
1011
1012    @Override
1013    public String getDeviceSvn() {
1014        return mImeiSv;
1015    }
1016
1017    @Override
1018    public IsimRecords getIsimRecords() {
1019        return mIsimUiccRecords;
1020    }
1021
1022    @Override
1023    public String getImei() {
1024        return mImei;
1025    }
1026
1027    @Override
1028    public String getEsn() {
1029        Rlog.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method");
1030        return "0";
1031    }
1032
1033    @Override
1034    public String getMeid() {
1035        Rlog.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method");
1036        return "0";
1037    }
1038
1039    @Override
1040    public String getSubscriberId() {
1041        IccRecords r = mIccRecords.get();
1042        return (r != null) ? r.getIMSI() : null;
1043    }
1044
1045    @Override
1046    public String getGroupIdLevel1() {
1047        IccRecords r = mIccRecords.get();
1048        return (r != null) ? r.getGid1() : null;
1049    }
1050
1051    @Override
1052    public String getLine1Number() {
1053        IccRecords r = mIccRecords.get();
1054        return (r != null) ? r.getMsisdnNumber() : null;
1055    }
1056
1057    @Override
1058    public String getMsisdn() {
1059        IccRecords r = mIccRecords.get();
1060        return (r != null) ? r.getMsisdnNumber() : null;
1061    }
1062
1063    @Override
1064    public String getLine1AlphaTag() {
1065        IccRecords r = mIccRecords.get();
1066        return (r != null) ? r.getMsisdnAlphaTag() : null;
1067    }
1068
1069    @Override
1070    public void setLine1Number(String alphaTag, String number, Message onComplete) {
1071        IccRecords r = mIccRecords.get();
1072        if (r != null) {
1073            r.setMsisdnNumber(alphaTag, number, onComplete);
1074        }
1075    }
1076
1077    @Override
1078    public void setVoiceMailNumber(String alphaTag,
1079                            String voiceMailNumber,
1080                            Message onComplete) {
1081
1082        Message resp;
1083        mVmNumber = voiceMailNumber;
1084        resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
1085        IccRecords r = mIccRecords.get();
1086        if (r != null) {
1087            r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
1088        }
1089    }
1090
1091    private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
1092        switch (commandInterfaceCFReason) {
1093        case CF_REASON_UNCONDITIONAL:
1094        case CF_REASON_BUSY:
1095        case CF_REASON_NO_REPLY:
1096        case CF_REASON_NOT_REACHABLE:
1097        case CF_REASON_ALL:
1098        case CF_REASON_ALL_CONDITIONAL:
1099            return true;
1100        default:
1101            return false;
1102        }
1103    }
1104
1105    public String getSystemProperty(String property, String defValue) {
1106        if(getUnitTestMode()) {
1107            return null;
1108        }
1109        return TelephonyManager.getTelephonyProperty(property, getSubId(), defValue);
1110    }
1111
1112    private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
1113        switch (commandInterfaceCFAction) {
1114        case CF_ACTION_DISABLE:
1115        case CF_ACTION_ENABLE:
1116        case CF_ACTION_REGISTRATION:
1117        case CF_ACTION_ERASURE:
1118            return true;
1119        default:
1120            return false;
1121        }
1122    }
1123
1124    public void updateDataConnectionTracker() {
1125        ((DcTracker)mDcTracker).update();
1126    }
1127
1128    protected  boolean isCfEnable(int action) {
1129        return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
1130    }
1131
1132    @Override
1133    public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
1134        ImsPhone imsPhone = mImsPhone;
1135        if ((imsPhone != null)
1136                && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1137            imsPhone.getCallForwardingOption(commandInterfaceCFReason, onComplete);
1138            return;
1139        }
1140
1141        if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
1142            if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "requesting call forwarding query.");
1143            Message resp;
1144            if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1145                resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete);
1146            } else {
1147                resp = onComplete;
1148            }
1149            mCi.queryCallForwardStatus(commandInterfaceCFReason,0,null,resp);
1150        }
1151    }
1152
1153    @Override
1154    public void setCallForwardingOption(int commandInterfaceCFAction,
1155            int commandInterfaceCFReason,
1156            String dialingNumber,
1157            int timerSeconds,
1158            Message onComplete) {
1159        ImsPhone imsPhone = mImsPhone;
1160        if ((imsPhone != null)
1161                && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1162            imsPhone.setCallForwardingOption(commandInterfaceCFAction,
1163                    commandInterfaceCFReason, dialingNumber, timerSeconds, onComplete);
1164            return;
1165        }
1166
1167        if (    (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
1168                (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
1169
1170            Message resp;
1171            if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
1172                Cfu cfu = new Cfu(dialingNumber, onComplete);
1173                resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
1174                        isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cfu);
1175            } else {
1176                resp = onComplete;
1177            }
1178            mCi.setCallForward(commandInterfaceCFAction,
1179                    commandInterfaceCFReason,
1180                    CommandsInterface.SERVICE_CLASS_VOICE,
1181                    dialingNumber,
1182                    timerSeconds,
1183                    resp);
1184        }
1185    }
1186
1187    @Override
1188    public void getOutgoingCallerIdDisplay(Message onComplete) {
1189        mCi.getCLIR(onComplete);
1190    }
1191
1192    @Override
1193    public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
1194                                           Message onComplete) {
1195        mCi.setCLIR(commandInterfaceCLIRMode,
1196                obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
1197    }
1198
1199    @Override
1200    public void getCallWaiting(Message onComplete) {
1201        ImsPhone imsPhone = mImsPhone;
1202        if ((imsPhone != null)
1203                && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1204            imsPhone.getCallWaiting(onComplete);
1205            return;
1206        }
1207
1208        //As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service
1209        //class parameter in call waiting interrogation  to network
1210        mCi.queryCallWaiting(CommandsInterface.SERVICE_CLASS_NONE, onComplete);
1211    }
1212
1213    @Override
1214    public void setCallWaiting(boolean enable, Message onComplete) {
1215        ImsPhone imsPhone = mImsPhone;
1216        if ((imsPhone != null)
1217                && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
1218            imsPhone.setCallWaiting(enable, onComplete);
1219            return;
1220        }
1221
1222        mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
1223    }
1224
1225    @Override
1226    public void
1227    getAvailableNetworks(Message response) {
1228        mCi.getAvailableNetworks(response);
1229    }
1230
1231    @Override
1232    public void
1233    getNeighboringCids(Message response) {
1234        mCi.getNeighboringCids(response);
1235    }
1236
1237    @Override
1238    public void setOnPostDialCharacter(Handler h, int what, Object obj) {
1239        mPostDialHandler = new Registrant(h, what, obj);
1240    }
1241
1242    @Override
1243    public void setMute(boolean muted) {
1244        mCT.setMute(muted);
1245    }
1246
1247    @Override
1248    public boolean getMute() {
1249        return mCT.getMute();
1250    }
1251
1252    @Override
1253    public void getDataCallList(Message response) {
1254        mCi.getDataCallList(response);
1255    }
1256
1257    @Override
1258    public void updateServiceLocation() {
1259        mSST.enableSingleLocationUpdate();
1260    }
1261
1262    @Override
1263    public void enableLocationUpdates() {
1264        mSST.enableLocationUpdates();
1265    }
1266
1267    @Override
1268    public void disableLocationUpdates() {
1269        mSST.disableLocationUpdates();
1270    }
1271
1272    @Override
1273    public boolean getDataRoamingEnabled() {
1274        return mDcTracker.getDataOnRoamingEnabled();
1275    }
1276
1277    @Override
1278    public void setDataRoamingEnabled(boolean enable) {
1279        mDcTracker.setDataOnRoamingEnabled(enable);
1280    }
1281
1282    @Override
1283    public boolean getDataEnabled() {
1284        return mDcTracker.getDataEnabled();
1285    }
1286
1287    @Override
1288    public void setDataEnabled(boolean enable) {
1289        mDcTracker.setDataEnabled(enable);
1290    }
1291
1292    /**
1293     * Removes the given MMI from the pending list and notifies
1294     * registrants that it is complete.
1295     * @param mmi MMI that is done
1296     */
1297    /*package*/ void
1298    onMMIDone(GsmMmiCode mmi) {
1299        /* Only notify complete if it's on the pending list.
1300         * Otherwise, it's already been handled (eg, previously canceled).
1301         * The exception is cancellation of an incoming USSD-REQUEST, which is
1302         * not on the list.
1303         */
1304        if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) {
1305            mMmiCompleteRegistrants.notifyRegistrants(
1306                new AsyncResult(null, mmi, null));
1307        }
1308    }
1309
1310
1311    private void
1312    onNetworkInitiatedUssd(GsmMmiCode mmi) {
1313        mMmiCompleteRegistrants.notifyRegistrants(
1314            new AsyncResult(null, mmi, null));
1315    }
1316
1317
1318    /** ussdMode is one of CommandsInterface.USSD_MODE_* */
1319    private void
1320    onIncomingUSSD (int ussdMode, String ussdMessage) {
1321        boolean isUssdError;
1322        boolean isUssdRequest;
1323
1324        isUssdRequest
1325            = (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
1326
1327        isUssdError
1328            = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
1329                && ussdMode != CommandsInterface.USSD_MODE_REQUEST);
1330
1331        // See comments in GsmMmiCode.java
1332        // USSD requests aren't finished until one
1333        // of these two events happen
1334        GsmMmiCode found = null;
1335        for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
1336            if(mPendingMMIs.get(i).isPendingUSSD()) {
1337                found = mPendingMMIs.get(i);
1338                break;
1339            }
1340        }
1341
1342        if (found != null) {
1343            // Complete pending USSD
1344
1345            if (isUssdError) {
1346                found.onUssdFinishedError();
1347            } else {
1348                found.onUssdFinished(ussdMessage, isUssdRequest);
1349            }
1350        } else { // pending USSD not found
1351            // The network may initiate its own USSD request
1352
1353            // ignore everything that isnt a Notify or a Request
1354            // also, discard if there is no message to present
1355            if (!isUssdError && ussdMessage != null) {
1356                GsmMmiCode mmi;
1357                mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
1358                                                   isUssdRequest,
1359                                                   GSMPhone.this,
1360                                                   mUiccApplication.get());
1361                onNetworkInitiatedUssd(mmi);
1362            }
1363        }
1364    }
1365
1366    /**
1367     * Make sure the network knows our preferred setting.
1368     */
1369    protected  void syncClirSetting() {
1370        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1371        int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
1372        if (clirSetting >= 0) {
1373            mCi.setCLIR(clirSetting, null);
1374        }
1375    }
1376
1377    @Override
1378    public void handleMessage (Message msg) {
1379        AsyncResult ar;
1380        Message onComplete;
1381
1382        if (!mIsTheCurrentActivePhone) {
1383            Rlog.e(LOG_TAG, "Received message " + msg +
1384                    "[" + msg.what + "] while being destroyed. Ignoring.");
1385            return;
1386        }
1387        switch (msg.what) {
1388            case EVENT_RADIO_AVAILABLE: {
1389                mCi.getBasebandVersion(
1390                        obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
1391
1392                mCi.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
1393                mCi.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
1394            }
1395            break;
1396
1397            case EVENT_RADIO_ON:
1398                // do-nothing
1399                break;
1400
1401            case EVENT_REGISTERED_TO_NETWORK:
1402                syncClirSetting();
1403                break;
1404
1405            case EVENT_SIM_RECORDS_LOADED:
1406                updateCurrentCarrierInProvider();
1407
1408                // Check if this is a different SIM than the previous one. If so unset the
1409                // voice mail number.
1410                String imsi = getVmSimImsi();
1411                String imsiFromSIM = getSubscriberId();
1412                if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
1413                    storeVoiceMailNumber(null);
1414                    setVmSimImsi(null);
1415                }
1416
1417                mSimRecordsLoadedRegistrants.notifyRegistrants();
1418            break;
1419
1420            case EVENT_GET_BASEBAND_VERSION_DONE:
1421                ar = (AsyncResult)msg.obj;
1422
1423                if (ar.exception != null) {
1424                    break;
1425                }
1426
1427                if (LOCAL_DEBUG) Rlog.d(LOG_TAG, "Baseband version: " + ar.result);
1428                setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result);
1429            break;
1430
1431            case EVENT_GET_IMEI_DONE:
1432                ar = (AsyncResult)msg.obj;
1433
1434                if (ar.exception != null) {
1435                    break;
1436                }
1437
1438                mImei = (String)ar.result;
1439            break;
1440
1441            case EVENT_GET_IMEISV_DONE:
1442                ar = (AsyncResult)msg.obj;
1443
1444                if (ar.exception != null) {
1445                    break;
1446                }
1447
1448                mImeiSv = (String)ar.result;
1449            break;
1450
1451            case EVENT_USSD:
1452                ar = (AsyncResult)msg.obj;
1453
1454                String[] ussdResult = (String[]) ar.result;
1455
1456                if (ussdResult.length > 1) {
1457                    try {
1458                        onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]);
1459                    } catch (NumberFormatException e) {
1460                        Rlog.w(LOG_TAG, "error parsing USSD");
1461                    }
1462                }
1463            break;
1464
1465            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: {
1466                // Some MMI requests (eg USSD) are not completed
1467                // within the course of a CommandsInterface request
1468                // If the radio shuts off or resets while one of these
1469                // is pending, we need to clean up.
1470
1471                for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
1472                    if (mPendingMMIs.get(i).isPendingUSSD()) {
1473                        mPendingMMIs.get(i).onUssdFinishedError();
1474                    }
1475                }
1476                ImsPhone imsPhone = mImsPhone;
1477                if (imsPhone != null) {
1478                    imsPhone.getServiceState().setStateOff();
1479                }
1480                break;
1481            }
1482
1483            case EVENT_SSN:
1484                ar = (AsyncResult)msg.obj;
1485                SuppServiceNotification not = (SuppServiceNotification) ar.result;
1486                mSsnRegistrants.notifyRegistrants(ar);
1487            break;
1488
1489            case EVENT_SET_CALL_FORWARD_DONE:
1490                ar = (AsyncResult)msg.obj;
1491                IccRecords r = mIccRecords.get();
1492                Cfu cfu = (Cfu) ar.userObj;
1493                if (ar.exception == null && r != null) {
1494                    r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cfu.mSetCfNumber);
1495                }
1496                if (cfu.mOnComplete != null) {
1497                    AsyncResult.forMessage(cfu.mOnComplete, ar.result, ar.exception);
1498                    cfu.mOnComplete.sendToTarget();
1499                }
1500                break;
1501
1502            case EVENT_SET_VM_NUMBER_DONE:
1503                ar = (AsyncResult)msg.obj;
1504                if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
1505                    storeVoiceMailNumber(mVmNumber);
1506                    ar.exception = null;
1507                }
1508                onComplete = (Message) ar.userObj;
1509                if (onComplete != null) {
1510                    AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1511                    onComplete.sendToTarget();
1512                }
1513                break;
1514
1515
1516            case EVENT_GET_CALL_FORWARD_DONE:
1517                ar = (AsyncResult)msg.obj;
1518                if (ar.exception == null) {
1519                    handleCfuQueryResult((CallForwardInfo[])ar.result);
1520                }
1521                onComplete = (Message) ar.userObj;
1522                if (onComplete != null) {
1523                    AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1524                    onComplete.sendToTarget();
1525                }
1526                break;
1527
1528            case EVENT_SET_NETWORK_AUTOMATIC:
1529                // Automatic network selection from EF_CSP SIM record
1530                ar = (AsyncResult) msg.obj;
1531                if (mSST.mSS.getIsManualSelection()) {
1532                    setNetworkSelectionModeAutomatic((Message) ar.result);
1533                    Rlog.d(LOG_TAG, "SET_NETWORK_SELECTION_AUTOMATIC: set to automatic");
1534                } else {
1535                    // prevent duplicate request which will push current PLMN to low priority
1536                    Rlog.d(LOG_TAG, "SET_NETWORK_SELECTION_AUTOMATIC: already automatic, ignore");
1537                }
1538                break;
1539
1540            case EVENT_ICC_RECORD_EVENTS:
1541                ar = (AsyncResult)msg.obj;
1542                processIccRecordEvents((Integer)ar.result);
1543                break;
1544
1545            case EVENT_SET_CLIR_COMPLETE:
1546                ar = (AsyncResult)msg.obj;
1547                if (ar.exception == null) {
1548                    saveClirSetting(msg.arg1);
1549                }
1550                onComplete = (Message) ar.userObj;
1551                if (onComplete != null) {
1552                    AsyncResult.forMessage(onComplete, ar.result, ar.exception);
1553                    onComplete.sendToTarget();
1554                }
1555                break;
1556
1557            case EVENT_SUBSCRIPTION_ACTIVATED:
1558                log("EVENT_SUBSCRIPTION_ACTIVATED");
1559                onSubscriptionActivated();
1560                break;
1561
1562            case EVENT_SUBSCRIPTION_DEACTIVATED:
1563                log("EVENT_SUBSCRIPTION_DEACTIVATED");
1564                onSubscriptionDeactivated();
1565                break;
1566
1567             default:
1568                 super.handleMessage(msg);
1569        }
1570    }
1571
1572    protected UiccCardApplication getUiccCardApplication() {
1573            return  ((UiccController) mUiccController).getUiccCardApplication(mPhoneId,
1574                    UiccController.APP_FAM_3GPP);
1575    }
1576
1577    @Override
1578    protected void onUpdateIccAvailability() {
1579        if (mUiccController == null ) {
1580            return;
1581        }
1582
1583        UiccCardApplication newUiccApplication =
1584                mUiccController.getUiccCardApplication(mPhoneId, UiccController.APP_FAM_IMS);
1585        IsimUiccRecords newIsimUiccRecords = null;
1586
1587        if (newUiccApplication != null) {
1588            newIsimUiccRecords = (IsimUiccRecords)newUiccApplication.getIccRecords();
1589            if (LOCAL_DEBUG) log("New ISIM application found");
1590        }
1591        mIsimUiccRecords = newIsimUiccRecords;
1592
1593        newUiccApplication = getUiccCardApplication();
1594
1595        UiccCardApplication app = mUiccApplication.get();
1596        if (app != newUiccApplication) {
1597            if (app != null) {
1598                if (LOCAL_DEBUG) log("Removing stale icc objects.");
1599                if (mIccRecords.get() != null) {
1600                    unregisterForSimRecordEvents();
1601                    mSimPhoneBookIntManager.updateIccRecords(null);
1602                }
1603                mIccRecords.set(null);
1604                mUiccApplication.set(null);
1605            }
1606            if (newUiccApplication != null) {
1607                if (LOCAL_DEBUG) log("New Uicc application found");
1608                mUiccApplication.set(newUiccApplication);
1609                mIccRecords.set(newUiccApplication.getIccRecords());
1610                registerForSimRecordEvents();
1611                mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get());
1612            }
1613        }
1614    }
1615
1616    private void processIccRecordEvents(int eventCode) {
1617        switch (eventCode) {
1618            case IccRecords.EVENT_CFI:
1619                notifyCallForwardingIndicator();
1620                break;
1621            case IccRecords.EVENT_MWI:
1622                notifyMessageWaitingIndicator();
1623                break;
1624        }
1625    }
1626
1627   /**
1628     * Sets the "current" field in the telephony provider according to the SIM's operator
1629     *
1630     * @return true for success; false otherwise.
1631     */
1632    public boolean updateCurrentCarrierInProvider() {
1633        long currentDds = SubscriptionManager.getDefaultDataSubId();
1634        String operatorNumeric = getOperatorNumeric();
1635
1636        log("updateCurrentCarrierInProvider: mSubId = " + getSubId()
1637                + " currentDds = " + currentDds + " operatorNumeric = " + operatorNumeric);
1638
1639        if (!TextUtils.isEmpty(operatorNumeric) && (getSubId() == currentDds)) {
1640            try {
1641                Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
1642                ContentValues map = new ContentValues();
1643                map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
1644                mContext.getContentResolver().insert(uri, map);
1645                return true;
1646            } catch (SQLException e) {
1647                Rlog.e(LOG_TAG, "Can't store current operator", e);
1648            }
1649        }
1650        return false;
1651    }
1652
1653    /**
1654     * Saves CLIR setting so that we can re-apply it as necessary
1655     * (in case the RIL resets it across reboots).
1656     */
1657    public void saveClirSetting(int commandInterfaceCLIRMode) {
1658        // open the shared preferences editor, and write the value.
1659        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
1660        SharedPreferences.Editor editor = sp.edit();
1661        editor.putInt(CLIR_KEY + getPhoneId(), commandInterfaceCLIRMode);
1662
1663        // commit and log the result.
1664        if (! editor.commit()) {
1665            Rlog.e(LOG_TAG, "failed to commit CLIR preference");
1666        }
1667    }
1668
1669    private void handleCfuQueryResult(CallForwardInfo[] infos) {
1670        IccRecords r = mIccRecords.get();
1671        if (r != null) {
1672            if (infos == null || infos.length == 0) {
1673                // Assume the default is not active
1674                // Set unconditional CFF in SIM to false
1675                r.setVoiceCallForwardingFlag(1, false, null);
1676            } else {
1677                for (int i = 0, s = infos.length; i < s; i++) {
1678                    if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
1679                        r.setVoiceCallForwardingFlag(1, (infos[i].status == 1),
1680                            infos[i].number);
1681                        // should only have the one
1682                        break;
1683                    }
1684                }
1685            }
1686        }
1687    }
1688
1689    /**
1690     * Retrieves the PhoneSubInfo of the GSMPhone
1691     */
1692    @Override
1693    public PhoneSubInfo getPhoneSubInfo(){
1694        return mSubInfo;
1695    }
1696
1697    /**
1698     * Retrieves the IccPhoneBookInterfaceManager of the GSMPhone
1699     */
1700    @Override
1701    public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
1702        return mSimPhoneBookIntManager;
1703    }
1704
1705    /**
1706     * Activate or deactivate cell broadcast SMS.
1707     *
1708     * @param activate 0 = activate, 1 = deactivate
1709     * @param response Callback message is empty on completion
1710     */
1711    @Override
1712    public void activateCellBroadcastSms(int activate, Message response) {
1713        Rlog.e(LOG_TAG, "[GSMPhone] activateCellBroadcastSms() is obsolete; use SmsManager");
1714        response.sendToTarget();
1715    }
1716
1717    /**
1718     * Query the current configuration of cdma cell broadcast SMS.
1719     *
1720     * @param response Callback message is empty on completion
1721     */
1722    @Override
1723    public void getCellBroadcastSmsConfig(Message response) {
1724        Rlog.e(LOG_TAG, "[GSMPhone] getCellBroadcastSmsConfig() is obsolete; use SmsManager");
1725        response.sendToTarget();
1726    }
1727
1728    /**
1729     * Configure cdma cell broadcast SMS.
1730     *
1731     * @param response Callback message is empty on completion
1732     */
1733    @Override
1734    public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
1735        Rlog.e(LOG_TAG, "[GSMPhone] setCellBroadcastSmsConfig() is obsolete; use SmsManager");
1736        response.sendToTarget();
1737    }
1738
1739    @Override
1740    public boolean isCspPlmnEnabled() {
1741        IccRecords r = mIccRecords.get();
1742        return (r != null) ? r.isCspPlmnEnabled() : false;
1743    }
1744
1745    private void registerForSimRecordEvents() {
1746        IccRecords r = mIccRecords.get();
1747        if (r == null) {
1748            return;
1749        }
1750        r.registerForNetworkSelectionModeAutomatic(
1751                this, EVENT_SET_NETWORK_AUTOMATIC, null);
1752        r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
1753        r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
1754    }
1755
1756    private void unregisterForSimRecordEvents() {
1757        IccRecords r = mIccRecords.get();
1758        if (r == null) {
1759            return;
1760        }
1761        r.unregisterForNetworkSelectionModeAutomatic(this);
1762        r.unregisterForRecordsEvents(this);
1763        r.unregisterForRecordsLoaded(this);
1764    }
1765
1766    @Override
1767    public void exitEmergencyCallbackMode() {
1768        if (mImsPhone != null) {
1769            mImsPhone.exitEmergencyCallbackMode();
1770        }
1771    }
1772
1773    @Override
1774    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1775        pw.println("GSMPhone extends:");
1776        super.dump(fd, pw, args);
1777        pw.println(" mCT=" + mCT);
1778        pw.println(" mSST=" + mSST);
1779        pw.println(" mPendingMMIs=" + mPendingMMIs);
1780        pw.println(" mSimPhoneBookIntManager=" + mSimPhoneBookIntManager);
1781        pw.println(" mSubInfo=" + mSubInfo);
1782        if (VDBG) pw.println(" mImei=" + mImei);
1783        if (VDBG) pw.println(" mImeiSv=" + mImeiSv);
1784        pw.println(" mVmNumber=" + mVmNumber);
1785    }
1786
1787    @Override
1788    public boolean setOperatorBrandOverride(String brand) {
1789        if (mUiccController == null) {
1790            return false;
1791        }
1792
1793        UiccCard card = mUiccController.getUiccCard();
1794        if (card == null) {
1795            return false;
1796        }
1797
1798        boolean status = card.setOperatorBrandOverride(brand);
1799
1800        // Refresh.
1801        if (status) {
1802            IccRecords iccRecords = mIccRecords.get();
1803            if (iccRecords != null) {
1804                SystemProperties.set(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA,
1805                        iccRecords.getServiceProviderName());
1806            }
1807            if (mSST != null) {
1808                mSST.pollState();
1809            }
1810        }
1811        return status;
1812    }
1813
1814    /**
1815     * @return operator numeric.
1816     */
1817    public String getOperatorNumeric() {
1818        String operatorNumeric = null;
1819        IccRecords r = mIccRecords.get();
1820        if (r != null) {
1821            operatorNumeric = r.getOperatorNumeric();
1822        }
1823        return operatorNumeric;
1824    }
1825
1826    public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
1827        ((DcTracker)mDcTracker)
1828                .registerForAllDataDisconnected(h, what, obj);
1829    }
1830
1831    public void unregisterForAllDataDisconnected(Handler h) {
1832        ((DcTracker)mDcTracker).unregisterForAllDataDisconnected(h);
1833    }
1834
1835    public void setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
1836        ((DcTracker)mDcTracker)
1837                .setInternalDataEnabled(enable, onCompleteMsg);
1838    }
1839
1840
1841    public boolean setInternalDataEnabledFlag(boolean enable) {
1842        return ((DcTracker)mDcTracker)
1843                .setInternalDataEnabledFlag(enable);
1844    }
1845
1846    public void notifyEcbmTimerReset(Boolean flag) {
1847        mEcmTimerResetRegistrants.notifyResult(flag);
1848    }
1849
1850    /**
1851     * Registration point for Ecm timer reset
1852     *
1853     * @param h handler to notify
1854     * @param what User-defined message code
1855     * @param obj placed in Message.obj
1856     */
1857    public void registerForEcmTimerReset(Handler h, int what, Object obj) {
1858        mEcmTimerResetRegistrants.addUnique(h, what, obj);
1859    }
1860
1861    public void unregisterForEcmTimerReset(Handler h) {
1862        mEcmTimerResetRegistrants.remove(h);
1863    }
1864
1865    public void resetSubSpecifics() {
1866    }
1867
1868    protected void log(String s) {
1869        Rlog.d(LOG_TAG, "[GSMPhone] " + s);
1870    }
1871}
1872