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