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