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