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