PhoneBase.java revision 850665a367489cce0b83431fa0e6e543b24062e0
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.internal.telephony;
19
20import android.content.Context;
21import android.content.SharedPreferences;
22import android.net.LinkCapabilities;
23import android.net.LinkProperties;
24import android.net.wifi.WifiManager;
25import android.os.AsyncResult;
26import android.os.Build;
27import android.os.Handler;
28import android.os.Looper;
29import android.os.Message;
30import android.os.RegistrantList;
31import android.os.SystemProperties;
32import android.preference.PreferenceManager;
33import android.provider.Settings;
34import android.telephony.CellInfo;
35import android.telephony.ServiceState;
36import android.telephony.SignalStrength;
37import android.text.TextUtils;
38import android.telephony.Rlog;
39
40import com.android.internal.R;
41import com.android.internal.telephony.dataconnection.DcTrackerBase;
42import com.android.internal.telephony.test.SimulatedRadioControl;
43import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
44import com.android.internal.telephony.uicc.IccFileHandler;
45import com.android.internal.telephony.uicc.IccRecords;
46import com.android.internal.telephony.uicc.IsimRecords;
47import com.android.internal.telephony.uicc.UiccCardApplication;
48import com.android.internal.telephony.uicc.UiccController;
49import com.android.internal.telephony.uicc.UsimServiceTable;
50import java.io.FileDescriptor;
51import java.io.PrintWriter;
52import java.util.List;
53import java.util.concurrent.atomic.AtomicReference;
54
55
56/**
57 * (<em>Not for SDK use</em>)
58 * A base implementation for the com.android.internal.telephony.Phone interface.
59 *
60 * Note that implementations of Phone.java are expected to be used
61 * from a single application thread. This should be the same thread that
62 * originally called PhoneFactory to obtain the interface.
63 *
64 *  {@hide}
65 *
66 */
67
68public abstract class PhoneBase extends Handler implements Phone {
69    private static final String LOG_TAG = "PhoneBase";
70
71    // Key used to read and write the saved network selection numeric value
72    public static final String NETWORK_SELECTION_KEY = "network_selection_key";
73    // Key used to read and write the saved network selection operator name
74    public static final String NETWORK_SELECTION_NAME_KEY = "network_selection_name_key";
75
76
77    // Key used to read/write "disable data connection on boot" pref (used for testing)
78    public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";
79
80    /* Event Constants */
81    protected static final int EVENT_RADIO_AVAILABLE             = 1;
82    /** Supplementary Service Notification received. */
83    protected static final int EVENT_SSN                         = 2;
84    protected static final int EVENT_SIM_RECORDS_LOADED          = 3;
85    protected static final int EVENT_MMI_DONE                    = 4;
86    protected static final int EVENT_RADIO_ON                    = 5;
87    protected static final int EVENT_GET_BASEBAND_VERSION_DONE   = 6;
88    protected static final int EVENT_USSD                        = 7;
89    protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE  = 8;
90    protected static final int EVENT_GET_IMEI_DONE               = 9;
91    protected static final int EVENT_GET_IMEISV_DONE             = 10;
92    protected static final int EVENT_GET_SIM_STATUS_DONE         = 11;
93    protected static final int EVENT_SET_CALL_FORWARD_DONE       = 12;
94    protected static final int EVENT_GET_CALL_FORWARD_DONE       = 13;
95    protected static final int EVENT_CALL_RING                   = 14;
96    protected static final int EVENT_CALL_RING_CONTINUE          = 15;
97
98    // Used to intercept the carrier selection calls so that
99    // we can save the values.
100    protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE    = 16;
101    protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 17;
102    protected static final int EVENT_SET_CLIR_COMPLETE              = 18;
103    protected static final int EVENT_REGISTERED_TO_NETWORK          = 19;
104    protected static final int EVENT_SET_VM_NUMBER_DONE             = 20;
105    // Events for CDMA support
106    protected static final int EVENT_GET_DEVICE_IDENTITY_DONE       = 21;
107    protected static final int EVENT_RUIM_RECORDS_LOADED            = 22;
108    protected static final int EVENT_NV_READY                       = 23;
109    protected static final int EVENT_SET_ENHANCED_VP                = 24;
110    protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER  = 25;
111    protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 26;
112    protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 27;
113    // other
114    protected static final int EVENT_SET_NETWORK_AUTOMATIC          = 28;
115    protected static final int EVENT_ICC_RECORD_EVENTS              = 29;
116    protected static final int EVENT_ICC_CHANGED                    = 30;
117
118    // Key used to read/write current CLIR setting
119    public static final String CLIR_KEY = "clir_key";
120
121    // Key used to read/write "disable DNS server check" pref (used for testing)
122    public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";
123
124    /* Instance Variables */
125    public CommandsInterface mCi;
126    boolean mDnsCheckDisabled;
127    public DcTrackerBase mDcTracker;
128    boolean mDoesRilSendMultipleCallRing;
129    int mCallRingContinueToken;
130    int mCallRingDelay;
131    public boolean mIsTheCurrentActivePhone = true;
132    boolean mIsVoiceCapable = true;
133    protected UiccController mUiccController = null;
134    public AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
135    public SmsStorageMonitor mSmsStorageMonitor;
136    public SmsUsageMonitor mSmsUsageMonitor;
137    protected AtomicReference<UiccCardApplication> mUiccApplication =
138            new AtomicReference<UiccCardApplication>();
139
140    private TelephonyTester mTelephonyTester;
141    private final String mName;
142    private final String mActionDetached;
143    private final String mActionAttached;
144
145    @Override
146    public String getPhoneName() {
147        return mName;
148    }
149
150    /**
151     * Return the ActionDetached string. When this action is received by components
152     * they are to simulate detaching from the network.
153     *
154     * @return com.android.internal.telephony.{mName}.action_detached
155     *          {mName} is GSM, CDMA ...
156     */
157    public String getActionDetached() {
158        return mActionDetached;
159    }
160
161    /**
162     * Return the ActionAttached string. When this action is received by components
163     * they are to simulate attaching to the network.
164     *
165     * @return com.android.internal.telephony.{mName}.action_detached
166     *          {mName} is GSM, CDMA ...
167     */
168    public String getActionAttached() {
169        return mActionAttached;
170    }
171
172    /**
173     * Set a system property, unless we're in unit test mode
174     */
175    public void setSystemProperty(String property, String value) {
176        if(getUnitTestMode()) {
177            return;
178        }
179        SystemProperties.set(property, value);
180    }
181
182
183    protected final RegistrantList mPreciseCallStateRegistrants
184            = new RegistrantList();
185
186    protected final RegistrantList mNewRingingConnectionRegistrants
187            = new RegistrantList();
188
189    protected final RegistrantList mIncomingRingRegistrants
190            = new RegistrantList();
191
192    protected final RegistrantList mDisconnectRegistrants
193            = new RegistrantList();
194
195    protected final RegistrantList mServiceStateRegistrants
196            = new RegistrantList();
197
198    protected final RegistrantList mMmiCompleteRegistrants
199            = new RegistrantList();
200
201    protected final RegistrantList mMmiRegistrants
202            = new RegistrantList();
203
204    protected final RegistrantList mUnknownConnectionRegistrants
205            = new RegistrantList();
206
207    protected final RegistrantList mSuppServiceFailedRegistrants
208            = new RegistrantList();
209
210    protected Looper mLooper; /* to insure registrants are in correct thread*/
211
212    protected final Context mContext;
213
214    /**
215     * PhoneNotifier is an abstraction for all system-wide
216     * state change notification. DefaultPhoneNotifier is
217     * used here unless running we're inside a unit test.
218     */
219    protected PhoneNotifier mNotifier;
220
221    protected SimulatedRadioControl mSimulatedRadioControl;
222
223    boolean mUnitTestMode;
224
225    /**
226     * Constructs a PhoneBase in normal (non-unit test) mode.
227     *
228     * @param notifier An instance of DefaultPhoneNotifier,
229     * @param context Context object from hosting application
230     * unless unit testing.
231     * @param ci the CommandsInterface
232     */
233    protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci) {
234        this(name, notifier, context, ci, false);
235    }
236
237    /**
238     * Constructs a PhoneBase in normal (non-unit test) mode.
239     *
240     * @param notifier An instance of DefaultPhoneNotifier,
241     * @param context Context object from hosting application
242     * unless unit testing.
243     * @param ci is CommandsInterface
244     * @param unitTestMode when true, prevents notifications
245     * of state change events
246     */
247    protected PhoneBase(String name, PhoneNotifier notifier, Context context, CommandsInterface ci,
248            boolean unitTestMode) {
249        mName = name;
250        mNotifier = notifier;
251        mContext = context;
252        mLooper = Looper.myLooper();
253        mCi = ci;
254        mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
255        mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
256
257        if (Build.IS_DEBUGGABLE) {
258            mTelephonyTester = new TelephonyTester(this);
259        }
260
261        setPropertiesByCarrier();
262
263        setUnitTestMode(unitTestMode);
264
265        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
266        mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
267        mCi.setOnCallRing(this, EVENT_CALL_RING, null);
268
269        /* "Voice capable" means that this device supports circuit-switched
270        * (i.e. voice) phone calls over the telephony network, and is allowed
271        * to display the in-call UI while a cellular voice call is active.
272        * This will be false on "data only" devices which can't make voice
273        * calls and don't support any in-call UI.
274        */
275        mIsVoiceCapable = mContext.getResources().getBoolean(
276                com.android.internal.R.bool.config_voice_capable);
277
278        /**
279         *  Some RIL's don't always send RIL_UNSOL_CALL_RING so it needs
280         *  to be generated locally. Ideally all ring tones should be loops
281         * and this wouldn't be necessary. But to minimize changes to upper
282         * layers it is requested that it be generated by lower layers.
283         *
284         * By default old phones won't have the property set but do generate
285         * the RIL_UNSOL_CALL_RING so the default if there is no property is
286         * true.
287         */
288        mDoesRilSendMultipleCallRing = SystemProperties.getBoolean(
289                TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true);
290        Rlog.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
291
292        mCallRingDelay = SystemProperties.getInt(
293                TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
294        Rlog.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
295
296        // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
297        mSmsStorageMonitor = new SmsStorageMonitor(this);
298        mSmsUsageMonitor = new SmsUsageMonitor(context);
299        mUiccController = UiccController.getInstance();
300        mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
301    }
302
303    @Override
304    public void dispose() {
305        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
306            mCi.unSetOnCallRing(this);
307            // Must cleanup all connectionS and needs to use sendMessage!
308            mDcTracker.cleanUpAllConnections(null);
309            mIsTheCurrentActivePhone = false;
310            // Dispose the SMS usage and storage monitors
311            mSmsStorageMonitor.dispose();
312            mSmsUsageMonitor.dispose();
313            mUiccController.unregisterForIccChanged(this);
314
315            if (mTelephonyTester != null) {
316                mTelephonyTester.dispose();
317            }
318        }
319    }
320
321    @Override
322    public void removeReferences() {
323        mSmsStorageMonitor = null;
324        mSmsUsageMonitor = null;
325        mIccRecords.set(null);
326        mUiccApplication.set(null);
327        mDcTracker = null;
328        mUiccController = null;
329    }
330
331    /**
332     * When overridden the derived class needs to call
333     * super.handleMessage(msg) so this method has a
334     * a chance to process the message.
335     *
336     * @param msg
337     */
338    @Override
339    public void handleMessage(Message msg) {
340        AsyncResult ar;
341
342        switch(msg.what) {
343            case EVENT_CALL_RING:
344                Rlog.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
345                ar = (AsyncResult)msg.obj;
346                if (ar.exception == null) {
347                    PhoneConstants.State state = getState();
348                    if ((!mDoesRilSendMultipleCallRing)
349                            && ((state == PhoneConstants.State.RINGING) ||
350                                    (state == PhoneConstants.State.IDLE))) {
351                        mCallRingContinueToken += 1;
352                        sendIncomingCallRingNotification(mCallRingContinueToken);
353                    } else {
354                        notifyIncomingRing();
355                    }
356                }
357                break;
358
359            case EVENT_CALL_RING_CONTINUE:
360                Rlog.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState());
361                if (getState() == PhoneConstants.State.RINGING) {
362                    sendIncomingCallRingNotification(msg.arg1);
363                }
364                break;
365
366            case EVENT_ICC_CHANGED:
367                onUpdateIccAvailability();
368                break;
369
370            default:
371                throw new RuntimeException("unexpected event not handled");
372        }
373    }
374
375    // Inherited documentation suffices.
376    @Override
377    public Context getContext() {
378        return mContext;
379    }
380
381    // Will be called when icc changed
382    protected abstract void onUpdateIccAvailability();
383
384    /**
385     * Disables the DNS check (i.e., allows "0.0.0.0").
386     * Useful for lab testing environment.
387     * @param b true disables the check, false enables.
388     */
389    @Override
390    public void disableDnsCheck(boolean b) {
391        mDnsCheckDisabled = b;
392        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
393        SharedPreferences.Editor editor = sp.edit();
394        editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b);
395        editor.apply();
396    }
397
398    /**
399     * Returns true if the DNS check is currently disabled.
400     */
401    @Override
402    public boolean isDnsCheckDisabled() {
403        return mDnsCheckDisabled;
404    }
405
406    // Inherited documentation suffices.
407    @Override
408    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {
409        checkCorrectThread(h);
410
411        mPreciseCallStateRegistrants.addUnique(h, what, obj);
412    }
413
414    // Inherited documentation suffices.
415    @Override
416    public void unregisterForPreciseCallStateChanged(Handler h) {
417        mPreciseCallStateRegistrants.remove(h);
418    }
419
420    /**
421     * Subclasses of Phone probably want to replace this with a
422     * version scoped to their packages
423     */
424    protected void notifyPreciseCallStateChangedP() {
425        AsyncResult ar = new AsyncResult(null, this, null);
426        mPreciseCallStateRegistrants.notifyRegistrants(ar);
427    }
428
429    // Inherited documentation suffices.
430    @Override
431    public void registerForUnknownConnection(Handler h, int what, Object obj) {
432        checkCorrectThread(h);
433
434        mUnknownConnectionRegistrants.addUnique(h, what, obj);
435    }
436
437    // Inherited documentation suffices.
438    @Override
439    public void unregisterForUnknownConnection(Handler h) {
440        mUnknownConnectionRegistrants.remove(h);
441    }
442
443    // Inherited documentation suffices.
444    @Override
445    public void registerForNewRingingConnection(
446            Handler h, int what, Object obj) {
447        checkCorrectThread(h);
448
449        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
450    }
451
452    // Inherited documentation suffices.
453    @Override
454    public void unregisterForNewRingingConnection(Handler h) {
455        mNewRingingConnectionRegistrants.remove(h);
456    }
457
458    // Inherited documentation suffices.
459    @Override
460    public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
461        mCi.registerForInCallVoicePrivacyOn(h,what,obj);
462    }
463
464    // Inherited documentation suffices.
465    @Override
466    public void unregisterForInCallVoicePrivacyOn(Handler h){
467        mCi.unregisterForInCallVoicePrivacyOn(h);
468    }
469
470    // Inherited documentation suffices.
471    @Override
472    public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
473        mCi.registerForInCallVoicePrivacyOff(h,what,obj);
474    }
475
476    // Inherited documentation suffices.
477    @Override
478    public void unregisterForInCallVoicePrivacyOff(Handler h){
479        mCi.unregisterForInCallVoicePrivacyOff(h);
480    }
481
482    // Inherited documentation suffices.
483    @Override
484    public void registerForIncomingRing(
485            Handler h, int what, Object obj) {
486        checkCorrectThread(h);
487
488        mIncomingRingRegistrants.addUnique(h, what, obj);
489    }
490
491    // Inherited documentation suffices.
492    @Override
493    public void unregisterForIncomingRing(Handler h) {
494        mIncomingRingRegistrants.remove(h);
495    }
496
497    // Inherited documentation suffices.
498    @Override
499    public void registerForDisconnect(Handler h, int what, Object obj) {
500        checkCorrectThread(h);
501
502        mDisconnectRegistrants.addUnique(h, what, obj);
503    }
504
505    // Inherited documentation suffices.
506    @Override
507    public void unregisterForDisconnect(Handler h) {
508        mDisconnectRegistrants.remove(h);
509    }
510
511    // Inherited documentation suffices.
512    @Override
513    public void registerForSuppServiceFailed(Handler h, int what, Object obj) {
514        checkCorrectThread(h);
515
516        mSuppServiceFailedRegistrants.addUnique(h, what, obj);
517    }
518
519    // Inherited documentation suffices.
520    @Override
521    public void unregisterForSuppServiceFailed(Handler h) {
522        mSuppServiceFailedRegistrants.remove(h);
523    }
524
525    // Inherited documentation suffices.
526    @Override
527    public void registerForMmiInitiate(Handler h, int what, Object obj) {
528        checkCorrectThread(h);
529
530        mMmiRegistrants.addUnique(h, what, obj);
531    }
532
533    // Inherited documentation suffices.
534    @Override
535    public void unregisterForMmiInitiate(Handler h) {
536        mMmiRegistrants.remove(h);
537    }
538
539    // Inherited documentation suffices.
540    @Override
541    public void registerForMmiComplete(Handler h, int what, Object obj) {
542        checkCorrectThread(h);
543
544        mMmiCompleteRegistrants.addUnique(h, what, obj);
545    }
546
547    // Inherited documentation suffices.
548    @Override
549    public void unregisterForMmiComplete(Handler h) {
550        checkCorrectThread(h);
551
552        mMmiCompleteRegistrants.remove(h);
553    }
554
555    /**
556     * Method to retrieve the saved operator id from the Shared Preferences
557     */
558    private String getSavedNetworkSelection() {
559        // open the shared preferences and search with our key.
560        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
561        return sp.getString(NETWORK_SELECTION_KEY, "");
562    }
563
564    /**
565     * Method to restore the previously saved operator id, or reset to
566     * automatic selection, all depending upon the value in the shared
567     * preferences.
568     */
569    public void restoreSavedNetworkSelection(Message response) {
570        // retrieve the operator id
571        String networkSelection = getSavedNetworkSelection();
572
573        // set to auto if the id is empty, otherwise select the network.
574        if (TextUtils.isEmpty(networkSelection)) {
575            mCi.setNetworkSelectionModeAutomatic(response);
576        } else {
577            mCi.setNetworkSelectionModeManual(networkSelection, response);
578        }
579    }
580
581    // Inherited documentation suffices.
582    @Override
583    public void setUnitTestMode(boolean f) {
584        mUnitTestMode = f;
585    }
586
587    // Inherited documentation suffices.
588    @Override
589    public boolean getUnitTestMode() {
590        return mUnitTestMode;
591    }
592
593    /**
594     * To be invoked when a voice call Connection disconnects.
595     *
596     * Subclasses of Phone probably want to replace this with a
597     * version scoped to their packages
598     */
599    protected void notifyDisconnectP(Connection cn) {
600        AsyncResult ar = new AsyncResult(null, cn, null);
601        mDisconnectRegistrants.notifyRegistrants(ar);
602    }
603
604    // Inherited documentation suffices.
605    @Override
606    public void registerForServiceStateChanged(
607            Handler h, int what, Object obj) {
608        checkCorrectThread(h);
609
610        mServiceStateRegistrants.add(h, what, obj);
611    }
612
613    // Inherited documentation suffices.
614    @Override
615    public void unregisterForServiceStateChanged(Handler h) {
616        mServiceStateRegistrants.remove(h);
617    }
618
619    // Inherited documentation suffices.
620    @Override
621    public void registerForRingbackTone(Handler h, int what, Object obj) {
622        mCi.registerForRingbackTone(h,what,obj);
623    }
624
625    // Inherited documentation suffices.
626    @Override
627    public void unregisterForRingbackTone(Handler h) {
628        mCi.unregisterForRingbackTone(h);
629    }
630
631    // Inherited documentation suffices.
632    @Override
633    public void registerForResendIncallMute(Handler h, int what, Object obj) {
634        mCi.registerForResendIncallMute(h,what,obj);
635    }
636
637    // Inherited documentation suffices.
638    @Override
639    public void unregisterForResendIncallMute(Handler h) {
640        mCi.unregisterForResendIncallMute(h);
641    }
642
643    @Override
644    public void setEchoSuppressionEnabled(boolean enabled) {
645        // no need for regular phone
646    }
647
648    /**
649     * Subclasses of Phone probably want to replace this with a
650     * version scoped to their packages
651     */
652    protected void notifyServiceStateChangedP(ServiceState ss) {
653        AsyncResult ar = new AsyncResult(null, ss, null);
654        mServiceStateRegistrants.notifyRegistrants(ar);
655
656        mNotifier.notifyServiceState(this);
657    }
658
659    // Inherited documentation suffices.
660    @Override
661    public SimulatedRadioControl getSimulatedRadioControl() {
662        return mSimulatedRadioControl;
663    }
664
665    /**
666     * Verifies the current thread is the same as the thread originally
667     * used in the initialization of this instance. Throws RuntimeException
668     * if not.
669     *
670     * @exception RuntimeException if the current thread is not
671     * the thread that originally obtained this PhoneBase instance.
672     */
673    private void checkCorrectThread(Handler h) {
674        if (h.getLooper() != mLooper) {
675            throw new RuntimeException(
676                    "com.android.internal.telephony.Phone must be used from within one thread");
677        }
678    }
679
680    /**
681     * Set the properties by matching the carrier string in
682     * a string-array resource
683     */
684    private void setPropertiesByCarrier() {
685        String carrier = SystemProperties.get("ro.carrier");
686
687        if (null == carrier || 0 == carrier.length() || "unknown".equals(carrier)) {
688            return;
689        }
690
691        CharSequence[] carrierLocales = mContext.
692                getResources().getTextArray(R.array.carrier_properties);
693
694        for (int i = 0; i < carrierLocales.length; i+=3) {
695            String c = carrierLocales[i].toString();
696            if (carrier.equals(c)) {
697                String l = carrierLocales[i+1].toString();
698
699                String language = l.substring(0, 2);
700                String country = "";
701                if (l.length() >=5) {
702                    country = l.substring(3, 5);
703                }
704                MccTable.setSystemLocale(mContext, language, country);
705
706                if (!country.isEmpty()) {
707                    try {
708                        Settings.Global.getInt(mContext.getContentResolver(),
709                                Settings.Global.WIFI_COUNTRY_CODE);
710                    } catch (Settings.SettingNotFoundException e) {
711                        // note this is not persisting
712                        WifiManager wM = (WifiManager)
713                                mContext.getSystemService(Context.WIFI_SERVICE);
714                        wM.setCountryCode(country, false);
715                    }
716                }
717                return;
718            }
719        }
720    }
721
722    /**
723     * Get state
724     */
725    @Override
726    public abstract PhoneConstants.State getState();
727
728    /**
729     * Retrieves the IccFileHandler of the Phone instance
730     */
731    public IccFileHandler getIccFileHandler(){
732        UiccCardApplication uiccApplication = mUiccApplication.get();
733        if (uiccApplication == null) return null;
734        return uiccApplication.getIccFileHandler();
735    }
736
737    /*
738     * Retrieves the Handler of the Phone instance
739     */
740    public Handler getHandler() {
741        return this;
742    }
743
744    /**
745    * Retrieves the ServiceStateTracker of the phone instance.
746    */
747    public ServiceStateTracker getServiceStateTracker() {
748        return null;
749    }
750
751    /**
752    * Get call tracker
753    */
754    public CallTracker getCallTracker() {
755        return null;
756    }
757
758    public AppType getCurrentUiccAppType() {
759        UiccCardApplication currentApp = mUiccApplication.get();
760        if (currentApp != null) {
761            return currentApp.getType();
762        }
763        return AppType.APPTYPE_UNKNOWN;
764    }
765
766    @Override
767    public IccCard getIccCard() {
768        return null;
769        //throw new Exception("getIccCard Shouldn't be called from PhoneBase");
770    }
771
772    @Override
773    public String getIccSerialNumber() {
774        IccRecords r = mIccRecords.get();
775        return (r != null) ? r.getIccId() : null;
776    }
777
778    @Override
779    public boolean getIccRecordsLoaded() {
780        IccRecords r = mIccRecords.get();
781        return (r != null) ? r.getRecordsLoaded() : false;
782    }
783
784    /**
785     * @return all available cell information or null if none.
786     */
787    @Override
788    public List<CellInfo> getAllCellInfo() {
789        return getServiceStateTracker().getAllCellInfo();
790    }
791
792    /**
793     * {@inheritDoc}
794     */
795    @Override
796    public void setCellInfoListRate(int rateInMillis) {
797        mCi.setCellInfoListRate(rateInMillis, null);
798    }
799
800    @Override
801    public boolean getMessageWaitingIndicator() {
802        IccRecords r = mIccRecords.get();
803        return (r != null) ? r.getVoiceMessageWaiting() : false;
804    }
805
806    @Override
807    public boolean getCallForwardingIndicator() {
808        IccRecords r = mIccRecords.get();
809        return (r != null) ? r.getVoiceCallForwardingFlag() : false;
810    }
811
812    /**
813     *  Query the status of the CDMA roaming preference
814     */
815    @Override
816    public void queryCdmaRoamingPreference(Message response) {
817        mCi.queryCdmaRoamingPreference(response);
818    }
819
820    /**
821     * Get the signal strength
822     */
823    @Override
824    public SignalStrength getSignalStrength() {
825        ServiceStateTracker sst = getServiceStateTracker();
826        if (sst == null) {
827            return new SignalStrength();
828        } else {
829            return sst.getSignalStrength();
830        }
831    }
832
833    /**
834     *  Set the status of the CDMA roaming preference
835     */
836    @Override
837    public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
838        mCi.setCdmaRoamingPreference(cdmaRoamingType, response);
839    }
840
841    /**
842     *  Set the status of the CDMA subscription mode
843     */
844    @Override
845    public void setCdmaSubscription(int cdmaSubscriptionType, Message response) {
846        mCi.setCdmaSubscriptionSource(cdmaSubscriptionType, response);
847    }
848
849    /**
850     *  Set the preferred Network Type: Global, CDMA only or GSM/UMTS only
851     */
852    @Override
853    public void setPreferredNetworkType(int networkType, Message response) {
854        mCi.setPreferredNetworkType(networkType, response);
855    }
856
857    @Override
858    public void getPreferredNetworkType(Message response) {
859        mCi.getPreferredNetworkType(response);
860    }
861
862    @Override
863    public void getSmscAddress(Message result) {
864        mCi.getSmscAddress(result);
865    }
866
867    @Override
868    public void setSmscAddress(String address, Message result) {
869        mCi.setSmscAddress(address, result);
870    }
871
872    @Override
873    public void setTTYMode(int ttyMode, Message onComplete) {
874        mCi.setTTYMode(ttyMode, onComplete);
875    }
876
877    @Override
878    public void queryTTYMode(Message onComplete) {
879        mCi.queryTTYMode(onComplete);
880    }
881
882    @Override
883    public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
884        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
885        logUnexpectedCdmaMethodCall("enableEnhancedVoicePrivacy");
886    }
887
888    @Override
889    public void getEnhancedVoicePrivacy(Message onComplete) {
890        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
891        logUnexpectedCdmaMethodCall("getEnhancedVoicePrivacy");
892    }
893
894    @Override
895    public void setBandMode(int bandMode, Message response) {
896        mCi.setBandMode(bandMode, response);
897    }
898
899    @Override
900    public void queryAvailableBandMode(Message response) {
901        mCi.queryAvailableBandMode(response);
902    }
903
904    @Override
905    public void invokeOemRilRequestRaw(byte[] data, Message response) {
906        mCi.invokeOemRilRequestRaw(data, response);
907    }
908
909    @Override
910    public void invokeOemRilRequestStrings(String[] strings, Message response) {
911        mCi.invokeOemRilRequestStrings(strings, response);
912    }
913
914    @Override
915    public void notifyDataActivity() {
916        mNotifier.notifyDataActivity(this);
917    }
918
919    public void notifyMessageWaitingIndicator() {
920        // Do not notify voice mail waiting if device doesn't support voice
921        if (!mIsVoiceCapable)
922            return;
923
924        // This function is added to send the notification to DefaultPhoneNotifier.
925        mNotifier.notifyMessageWaitingChanged(this);
926    }
927
928    public void notifyDataConnection(String reason, String apnType,
929            PhoneConstants.DataState state) {
930        mNotifier.notifyDataConnection(this, reason, apnType, state);
931    }
932
933    public void notifyDataConnection(String reason, String apnType) {
934        mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
935    }
936
937    public void notifyDataConnection(String reason) {
938        String types[] = getActiveApnTypes();
939        for (String apnType : types) {
940            mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));
941        }
942    }
943
944    public void notifyOtaspChanged(int otaspMode) {
945        mNotifier.notifyOtaspChanged(this, otaspMode);
946    }
947
948    public void notifySignalStrength() {
949        mNotifier.notifySignalStrength(this);
950    }
951
952    public void notifyCellInfo(List<CellInfo> cellInfo) {
953        mNotifier.notifyCellInfo(this, cellInfo);
954    }
955
956    /**
957     * @return true if a mobile originating emergency call is active
958     */
959    public boolean isInEmergencyCall() {
960        return false;
961    }
962
963    /**
964     * @return true if we are in the emergency call back mode. This is a period where
965     * the phone should be using as little power as possible and be ready to receive an
966     * incoming call from the emergency operator.
967     */
968    public boolean isInEcm() {
969        return false;
970    }
971
972    @Override
973    public abstract int getPhoneType();
974
975    /** @hide */
976    @Override
977    public int getVoiceMessageCount(){
978        return 0;
979    }
980
981    /**
982     * Returns the CDMA ERI icon index to display
983     */
984    @Override
985    public int getCdmaEriIconIndex() {
986        logUnexpectedCdmaMethodCall("getCdmaEriIconIndex");
987        return -1;
988    }
989
990    /**
991     * Returns the CDMA ERI icon mode,
992     * 0 - ON
993     * 1 - FLASHING
994     */
995    @Override
996    public int getCdmaEriIconMode() {
997        logUnexpectedCdmaMethodCall("getCdmaEriIconMode");
998        return -1;
999    }
1000
1001    /**
1002     * Returns the CDMA ERI text,
1003     */
1004    @Override
1005    public String getCdmaEriText() {
1006        logUnexpectedCdmaMethodCall("getCdmaEriText");
1007        return "GSM nw, no ERI";
1008    }
1009
1010    @Override
1011    public String getCdmaMin() {
1012        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1013        logUnexpectedCdmaMethodCall("getCdmaMin");
1014        return null;
1015    }
1016
1017    @Override
1018    public boolean isMinInfoReady() {
1019        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1020        logUnexpectedCdmaMethodCall("isMinInfoReady");
1021        return false;
1022    }
1023
1024    @Override
1025    public String getCdmaPrlVersion(){
1026        //  This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1027        logUnexpectedCdmaMethodCall("getCdmaPrlVersion");
1028        return null;
1029    }
1030
1031    @Override
1032    public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
1033        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1034        logUnexpectedCdmaMethodCall("sendBurstDtmf");
1035    }
1036
1037    @Override
1038    public void exitEmergencyCallbackMode() {
1039        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1040        logUnexpectedCdmaMethodCall("exitEmergencyCallbackMode");
1041    }
1042
1043    @Override
1044    public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) {
1045        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1046        logUnexpectedCdmaMethodCall("registerForCdmaOtaStatusChange");
1047    }
1048
1049    @Override
1050    public void unregisterForCdmaOtaStatusChange(Handler h) {
1051        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1052        logUnexpectedCdmaMethodCall("unregisterForCdmaOtaStatusChange");
1053    }
1054
1055    @Override
1056    public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) {
1057        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1058        logUnexpectedCdmaMethodCall("registerForSubscriptionInfoReady");
1059    }
1060
1061    @Override
1062    public void unregisterForSubscriptionInfoReady(Handler h) {
1063        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1064        logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady");
1065    }
1066
1067    /**
1068     * Returns true if OTA Service Provisioning needs to be performed.
1069     * If not overridden return false.
1070     */
1071    @Override
1072    public boolean needsOtaServiceProvisioning() {
1073        return false;
1074    }
1075
1076    /**
1077     * Return true if number is an OTASP number.
1078     * If not overridden return false.
1079     */
1080    @Override
1081    public  boolean isOtaSpNumber(String dialStr) {
1082        return false;
1083    }
1084
1085    @Override
1086    public void registerForCallWaiting(Handler h, int what, Object obj){
1087        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1088        logUnexpectedCdmaMethodCall("registerForCallWaiting");
1089    }
1090
1091    @Override
1092    public void unregisterForCallWaiting(Handler h){
1093        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1094        logUnexpectedCdmaMethodCall("unregisterForCallWaiting");
1095    }
1096
1097    @Override
1098    public void registerForEcmTimerReset(Handler h, int what, Object obj) {
1099        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1100        logUnexpectedCdmaMethodCall("registerForEcmTimerReset");
1101    }
1102
1103    @Override
1104    public void unregisterForEcmTimerReset(Handler h) {
1105        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1106        logUnexpectedCdmaMethodCall("unregisterForEcmTimerReset");
1107    }
1108
1109    @Override
1110    public void registerForSignalInfo(Handler h, int what, Object obj) {
1111        mCi.registerForSignalInfo(h, what, obj);
1112    }
1113
1114    @Override
1115    public void unregisterForSignalInfo(Handler h) {
1116        mCi.unregisterForSignalInfo(h);
1117    }
1118
1119    @Override
1120    public void registerForDisplayInfo(Handler h, int what, Object obj) {
1121        mCi.registerForDisplayInfo(h, what, obj);
1122    }
1123
1124     @Override
1125    public void unregisterForDisplayInfo(Handler h) {
1126         mCi.unregisterForDisplayInfo(h);
1127     }
1128
1129    @Override
1130    public void registerForNumberInfo(Handler h, int what, Object obj) {
1131        mCi.registerForNumberInfo(h, what, obj);
1132    }
1133
1134    @Override
1135    public void unregisterForNumberInfo(Handler h) {
1136        mCi.unregisterForNumberInfo(h);
1137    }
1138
1139    @Override
1140    public void registerForRedirectedNumberInfo(Handler h, int what, Object obj) {
1141        mCi.registerForRedirectedNumberInfo(h, what, obj);
1142    }
1143
1144    @Override
1145    public void unregisterForRedirectedNumberInfo(Handler h) {
1146        mCi.unregisterForRedirectedNumberInfo(h);
1147    }
1148
1149    @Override
1150    public void registerForLineControlInfo(Handler h, int what, Object obj) {
1151        mCi.registerForLineControlInfo( h, what, obj);
1152    }
1153
1154    @Override
1155    public void unregisterForLineControlInfo(Handler h) {
1156        mCi.unregisterForLineControlInfo(h);
1157    }
1158
1159    @Override
1160    public void registerFoT53ClirlInfo(Handler h, int what, Object obj) {
1161        mCi.registerFoT53ClirlInfo(h, what, obj);
1162    }
1163
1164    @Override
1165    public void unregisterForT53ClirInfo(Handler h) {
1166        mCi.unregisterForT53ClirInfo(h);
1167    }
1168
1169    @Override
1170    public void registerForT53AudioControlInfo(Handler h, int what, Object obj) {
1171        mCi.registerForT53AudioControlInfo( h, what, obj);
1172    }
1173
1174    @Override
1175    public void unregisterForT53AudioControlInfo(Handler h) {
1176        mCi.unregisterForT53AudioControlInfo(h);
1177    }
1178
1179     @Override
1180    public void setOnEcbModeExitResponse(Handler h, int what, Object obj){
1181         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1182         logUnexpectedCdmaMethodCall("setOnEcbModeExitResponse");
1183     }
1184
1185     @Override
1186    public void unsetOnEcbModeExitResponse(Handler h){
1187        // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
1188         logUnexpectedCdmaMethodCall("unsetOnEcbModeExitResponse");
1189     }
1190
1191    @Override
1192    public String[] getActiveApnTypes() {
1193        return mDcTracker.getActiveApnTypes();
1194    }
1195
1196    @Override
1197    public String getActiveApnHost(String apnType) {
1198        return mDcTracker.getActiveApnString(apnType);
1199    }
1200
1201    @Override
1202    public LinkProperties getLinkProperties(String apnType) {
1203        return mDcTracker.getLinkProperties(apnType);
1204    }
1205
1206    @Override
1207    public LinkCapabilities getLinkCapabilities(String apnType) {
1208        return mDcTracker.getLinkCapabilities(apnType);
1209    }
1210
1211    @Override
1212    public int enableApnType(String type) {
1213        return mDcTracker.enableApnType(type);
1214    }
1215
1216    @Override
1217    public int disableApnType(String type) {
1218        return mDcTracker.disableApnType(type);
1219    }
1220
1221    @Override
1222    public boolean isDataConnectivityPossible() {
1223        return isDataConnectivityPossible(PhoneConstants.APN_TYPE_DEFAULT);
1224    }
1225
1226    @Override
1227    public boolean isDataConnectivityPossible(String apnType) {
1228        return ((mDcTracker != null) &&
1229                (mDcTracker.isDataPossible(apnType)));
1230    }
1231
1232    /**
1233     * Notify registrants of a new ringing Connection.
1234     * Subclasses of Phone probably want to replace this with a
1235     * version scoped to their packages
1236     */
1237    protected void notifyNewRingingConnectionP(Connection cn) {
1238        if (!mIsVoiceCapable)
1239            return;
1240        AsyncResult ar = new AsyncResult(null, cn, null);
1241        mNewRingingConnectionRegistrants.notifyRegistrants(ar);
1242    }
1243
1244    /**
1245     * Notify registrants of a RING event.
1246     */
1247    private void notifyIncomingRing() {
1248        if (!mIsVoiceCapable)
1249            return;
1250        AsyncResult ar = new AsyncResult(null, this, null);
1251        mIncomingRingRegistrants.notifyRegistrants(ar);
1252    }
1253
1254    /**
1255     * Send the incoming call Ring notification if conditions are right.
1256     */
1257    private void sendIncomingCallRingNotification(int token) {
1258        if (mIsVoiceCapable && !mDoesRilSendMultipleCallRing &&
1259                (token == mCallRingContinueToken)) {
1260            Rlog.d(LOG_TAG, "Sending notifyIncomingRing");
1261            notifyIncomingRing();
1262            sendMessageDelayed(
1263                    obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay);
1264        } else {
1265            Rlog.d(LOG_TAG, "Ignoring ring notification request,"
1266                    + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing
1267                    + " token=" + token
1268                    + " mCallRingContinueToken=" + mCallRingContinueToken
1269                    + " mIsVoiceCapable=" + mIsVoiceCapable);
1270        }
1271    }
1272
1273    @Override
1274    public boolean isCspPlmnEnabled() {
1275        // This function should be overridden by the class GSMPhone.
1276        // Not implemented in CDMAPhone.
1277        logUnexpectedGsmMethodCall("isCspPlmnEnabled");
1278        return false;
1279    }
1280
1281    @Override
1282    public IsimRecords getIsimRecords() {
1283        Rlog.e(LOG_TAG, "getIsimRecords() is only supported on LTE devices");
1284        return null;
1285    }
1286
1287    @Override
1288    public void requestIsimAuthentication(String nonce, Message result) {
1289        Rlog.e(LOG_TAG, "requestIsimAuthentication() is only supported on LTE devices");
1290    }
1291
1292    @Override
1293    public String getMsisdn() {
1294        logUnexpectedGsmMethodCall("getMsisdn");
1295        return null;
1296    }
1297
1298    /**
1299     * Common error logger method for unexpected calls to CDMA-only methods.
1300     */
1301    private static void logUnexpectedCdmaMethodCall(String name)
1302    {
1303        Rlog.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
1304                "called, CDMAPhone inactive.");
1305    }
1306
1307    @Override
1308    public PhoneConstants.DataState getDataConnectionState() {
1309        return getDataConnectionState(PhoneConstants.APN_TYPE_DEFAULT);
1310    }
1311
1312    /**
1313     * Common error logger method for unexpected calls to GSM/WCDMA-only methods.
1314     */
1315    private static void logUnexpectedGsmMethodCall(String name) {
1316        Rlog.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
1317                "called, GSMPhone inactive.");
1318    }
1319
1320    // Called by SimRecords which is constructed with a PhoneBase instead of a GSMPhone.
1321    public void notifyCallForwardingIndicator() {
1322        // This function should be overridden by the class GSMPhone. Not implemented in CDMAPhone.
1323        Rlog.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
1324    }
1325
1326    public void notifyDataConnectionFailed(String reason, String apnType) {
1327        mNotifier.notifyDataConnectionFailed(this, reason, apnType);
1328    }
1329
1330    /**
1331     * {@inheritDoc}
1332     */
1333    @Override
1334    public int getLteOnCdmaMode() {
1335        return mCi.getLteOnCdmaMode();
1336    }
1337
1338    /**
1339     * Sets the SIM voice message waiting indicator records.
1340     * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
1341     * @param countWaiting The number of messages waiting, if known. Use
1342     *                     -1 to indicate that an unknown number of
1343     *                      messages are waiting
1344     */
1345    @Override
1346    public void setVoiceMessageWaiting(int line, int countWaiting) {
1347        IccRecords r = mIccRecords.get();
1348        if (r != null) {
1349            r.setVoiceMessageWaiting(line, countWaiting);
1350        }
1351    }
1352
1353    /**
1354     * Gets the USIM service table from the UICC, if present and available.
1355     * @return an interface to the UsimServiceTable record, or null if not available
1356     */
1357    @Override
1358    public UsimServiceTable getUsimServiceTable() {
1359        IccRecords r = mIccRecords.get();
1360        return (r != null) ? r.getUsimServiceTable() : null;
1361    }
1362
1363    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1364        pw.println("PhoneBase:");
1365        pw.println(" mCi=" + mCi);
1366        pw.println(" mDnsCheckDisabled=" + mDnsCheckDisabled);
1367        pw.println(" mDcTracker=" + mDcTracker);
1368        pw.println(" mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing);
1369        pw.println(" mCallRingContinueToken=" + mCallRingContinueToken);
1370        pw.println(" mCallRingDelay=" + mCallRingDelay);
1371        pw.println(" mIsTheCurrentActivePhone=" + mIsTheCurrentActivePhone);
1372        pw.println(" mIsVoiceCapable=" + mIsVoiceCapable);
1373        pw.println(" mIccRecords=" + mIccRecords.get());
1374        pw.println(" mUiccApplication=" + mUiccApplication.get());
1375        pw.println(" mSmsStorageMonitor=" + mSmsStorageMonitor);
1376        pw.println(" mSmsUsageMonitor=" + mSmsUsageMonitor);
1377        pw.flush();
1378        pw.println(" mLooper=" + mLooper);
1379        pw.println(" mContext=" + mContext);
1380        pw.println(" mNotifier=" + mNotifier);
1381        pw.println(" mSimulatedRadioControl=" + mSimulatedRadioControl);
1382        pw.println(" mUnitTestMode=" + mUnitTestMode);
1383        pw.println(" isDnsCheckDisabled()=" + isDnsCheckDisabled());
1384        pw.println(" getUnitTestMode()=" + getUnitTestMode());
1385        pw.println(" getState()=" + getState());
1386        pw.println(" getIccSerialNumber()=" + getIccSerialNumber());
1387        pw.println(" getIccRecordsLoaded()=" + getIccRecordsLoaded());
1388        pw.println(" getMessageWaitingIndicator()=" + getMessageWaitingIndicator());
1389        pw.println(" getCallForwardingIndicator()=" + getCallForwardingIndicator());
1390        pw.println(" isInEmergencyCall()=" + isInEmergencyCall());
1391        pw.flush();
1392        pw.println(" isInEcm()=" + isInEcm());
1393        pw.println(" getPhoneName()=" + getPhoneName());
1394        pw.println(" getPhoneType()=" + getPhoneType());
1395        pw.println(" getVoiceMessageCount()=" + getVoiceMessageCount());
1396        pw.println(" getActiveApnTypes()=" + getActiveApnTypes());
1397        pw.println(" isDataConnectivityPossible()=" + isDataConnectivityPossible());
1398        pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning());
1399    }
1400}
1401