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