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