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