Home | History | Annotate | Download | only in telephony
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony;
     18 
     19 import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DEFAULT_SUBSCRIPTION;
     20 
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.net.LocalServerSocket;
     25 import android.os.SystemProperties;
     26 import android.os.UserHandle;
     27 import android.provider.Settings;
     28 import android.provider.Settings.SettingNotFoundException;
     29 import android.telephony.Rlog;
     30 import android.telephony.SubscriptionManager;
     31 import android.telephony.TelephonyManager;
     32 
     33 import com.android.internal.telephony.cdma.CDMALTEPhone;
     34 import com.android.internal.telephony.cdma.CDMAPhone;
     35 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
     36 import com.android.internal.telephony.gsm.GSMPhone;
     37 import com.android.internal.telephony.imsphone.ImsPhone;
     38 import com.android.internal.telephony.imsphone.ImsPhoneFactory;
     39 import com.android.internal.telephony.sip.SipPhone;
     40 import com.android.internal.telephony.sip.SipPhoneFactory;
     41 import com.android.internal.telephony.uicc.UiccController;
     42 
     43 /**
     44  * {@hide}
     45  */
     46 public class PhoneFactory {
     47     static final String LOG_TAG = "PhoneFactory";
     48     static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000;
     49     static final int SOCKET_OPEN_MAX_RETRY = 3;
     50 
     51     //***** Class Variables
     52 
     53     // lock sLockProxyPhones protects both sProxyPhones and sProxyPhone
     54     final static Object sLockProxyPhones = new Object();
     55     static private PhoneProxy[] sProxyPhones = null;
     56     static private PhoneProxy sProxyPhone = null;
     57 
     58     static private CommandsInterface[] sCommandsInterfaces = null;
     59 
     60     static private ProxyController mProxyController;
     61     static private UiccController mUiccController;
     62 
     63     static private CommandsInterface sCommandsInterface = null;
     64     static private SubInfoRecordUpdater sSubInfoRecordUpdater = null;
     65 
     66     static private boolean sMadeDefaults = false;
     67     static private PhoneNotifier sPhoneNotifier;
     68     static private Context sContext;
     69 
     70     //***** Class Methods
     71 
     72     public static void makeDefaultPhones(Context context) {
     73         makeDefaultPhone(context);
     74     }
     75 
     76     /**
     77      * FIXME replace this with some other way of making these
     78      * instances
     79      */
     80     public static void makeDefaultPhone(Context context) {
     81         synchronized (sLockProxyPhones) {
     82             if (!sMadeDefaults) {
     83                 sContext = context;
     84 
     85                 // create the telephony device controller.
     86                 TelephonyDevController.create();
     87 
     88                 int retryCount = 0;
     89                 for(;;) {
     90                     boolean hasException = false;
     91                     retryCount ++;
     92 
     93                     try {
     94                         // use UNIX domain socket to
     95                         // prevent subsequent initialization
     96                         new LocalServerSocket("com.android.internal.telephony");
     97                     } catch (java.io.IOException ex) {
     98                         hasException = true;
     99                     }
    100 
    101                     if ( !hasException ) {
    102                         break;
    103                     } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
    104                         throw new RuntimeException("PhoneFactory probably already running");
    105                     } else {
    106                         try {
    107                             Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
    108                         } catch (InterruptedException er) {
    109                         }
    110                     }
    111                 }
    112 
    113                 sPhoneNotifier = new DefaultPhoneNotifier();
    114 
    115                 // Get preferred network mode
    116                 int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
    117                 if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
    118                     preferredNetworkMode = Phone.NT_MODE_GLOBAL;
    119                 }
    120 
    121                 int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
    122                 Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
    123 
    124                 /* In case of multi SIM mode two instances of PhoneProxy, RIL are created,
    125                    where as in single SIM mode only instance. isMultiSimEnabled() function checks
    126                    whether it is single SIM or multi SIM mode */
    127                 int numPhones = TelephonyManager.getDefault().getPhoneCount();
    128                 int[] networkModes = new int[numPhones];
    129                 sProxyPhones = new PhoneProxy[numPhones];
    130                 sCommandsInterfaces = new RIL[numPhones];
    131 
    132                 for (int i = 0; i < numPhones; i++) {
    133                     //reads the system properties and makes commandsinterface
    134                     try {
    135 //                        // Get preferred network type.
    136 //                        TODO: Sishir added this code to but we need a new technique for MSim
    137 //                        int networkType = calculatePreferredNetworkType(context);
    138 //                        Rlog.i(LOG_TAG, "Network Type set to " + Integer.toString(networkType));
    139 
    140                         networkModes[i]  = TelephonyManager.getIntAtIndex(
    141                                 context.getContentResolver(),
    142                                 Settings.Global.PREFERRED_NETWORK_MODE, i);
    143                     } catch (SettingNotFoundException snfe) {
    144                         Rlog.e(LOG_TAG, "Settings Exception Reading Value At Index for"+
    145                                 " Settings.Global.PREFERRED_NETWORK_MODE");
    146                         networkModes[i] = preferredNetworkMode;
    147                     }
    148 
    149                     Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
    150                     sCommandsInterfaces[i] = new RIL(context, networkModes[i],
    151                             cdmaSubscription, i);
    152                 }
    153                 Rlog.i(LOG_TAG, "Creating SubscriptionController");
    154                 SubscriptionController.init(context, sCommandsInterfaces);
    155 
    156                 // Instantiate UiccController so that all other classes can just
    157                 // call getInstance()
    158                 mUiccController = UiccController.make(context, sCommandsInterfaces);
    159 
    160                 for (int i = 0; i < numPhones; i++) {
    161                     PhoneBase phone = null;
    162                     int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
    163                     if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
    164                         phone = new GSMPhone(context,
    165                                 sCommandsInterfaces[i], sPhoneNotifier, i);
    166                     } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
    167                         phone = new CDMALTEPhone(context,
    168                                 sCommandsInterfaces[i], sPhoneNotifier, i);
    169                     }
    170                     Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
    171 
    172                     sProxyPhones[i] = new PhoneProxy(phone);
    173                 }
    174                 mProxyController = ProxyController.getInstance(context, sProxyPhones,
    175                         mUiccController, sCommandsInterfaces);
    176 
    177                 // Set the default phone in base class.
    178                 // FIXME: This is a first best guess at what the defaults will be. It
    179                 // FIXME: needs to be done in a more controlled manner in the future.
    180                 sProxyPhone = sProxyPhones[0];
    181                 sCommandsInterface = sCommandsInterfaces[0];
    182 
    183                 // Ensure that we have a default SMS app. Requesting the app with
    184                 // updateIfNeeded set to true is enough to configure a default SMS app.
    185                 ComponentName componentName =
    186                         SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */);
    187                 String packageName = "NONE";
    188                 if (componentName != null) {
    189                     packageName = componentName.getPackageName();
    190                 }
    191                 Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);
    192 
    193                 // Set up monitor to watch for changes to SMS packages
    194                 SmsApplication.initSmsPackageMonitor(context);
    195 
    196                 sMadeDefaults = true;
    197 
    198                 Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
    199                 sSubInfoRecordUpdater = new SubInfoRecordUpdater(context,
    200                         sProxyPhones, sCommandsInterfaces);
    201                 SubscriptionController.getInstance().updatePhonesAvailability(sProxyPhones);
    202             }
    203         }
    204     }
    205 
    206     public static Phone getCdmaPhone(int phoneId) {
    207         Phone phone;
    208         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    209             phone = new CDMALTEPhone(sContext, sCommandsInterfaces[phoneId],
    210                     sPhoneNotifier, phoneId);
    211         }
    212         return phone;
    213     }
    214 
    215     public static Phone getGsmPhone(int phoneId) {
    216         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    217             Phone phone = new GSMPhone(sContext, sCommandsInterfaces[phoneId],
    218                     sPhoneNotifier, phoneId);
    219             return phone;
    220         }
    221     }
    222 
    223     public static Phone getDefaultPhone() {
    224         synchronized (sLockProxyPhones) {
    225             if (!sMadeDefaults) {
    226                 throw new IllegalStateException("Default phones haven't been made yet!");
    227             }
    228             return sProxyPhone;
    229         }
    230     }
    231 
    232     public static Phone getPhone(int phoneId) {
    233         Phone phone;
    234         synchronized (sLockProxyPhones) {
    235             if (!sMadeDefaults) {
    236                 throw new IllegalStateException("Default phones haven't been made yet!");
    237                 // CAF_MSIM FIXME need to introduce default phone id ?
    238             } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_ID) {
    239                 Rlog.d(LOG_TAG, "getPhone: phoneId == DEFAULT_PHONE_ID");
    240                 phone = sProxyPhone;
    241             } else {
    242                 Rlog.d(LOG_TAG, "getPhone: phoneId != DEFAULT_PHONE_ID");
    243                 phone = (((phoneId >= 0)
    244                                 && (phoneId < TelephonyManager.getDefault().getPhoneCount()))
    245                         ? sProxyPhones[phoneId] : null);
    246             }
    247             Rlog.d(LOG_TAG, "getPhone:- phone=" + phone);
    248             return phone;
    249         }
    250     }
    251 
    252     public static Phone[] getPhones() {
    253         synchronized (sLockProxyPhones) {
    254             if (!sMadeDefaults) {
    255                 throw new IllegalStateException("Default phones haven't been made yet!");
    256             }
    257             return sProxyPhones;
    258         }
    259     }
    260 
    261     public static Phone getCdmaPhone() {
    262         if (!sMadeDefaults) {
    263             throw new IllegalStateException("Default phones haven't been made yet!");
    264         }
    265         Phone phone;
    266         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    267             switch (TelephonyManager.getLteOnCdmaModeStatic()) {
    268                 case PhoneConstants.LTE_ON_CDMA_TRUE: {
    269                     phone = new CDMALTEPhone(sContext, sCommandsInterface, sPhoneNotifier);
    270                     break;
    271                 }
    272                 case PhoneConstants.LTE_ON_CDMA_FALSE:
    273                 case PhoneConstants.LTE_ON_CDMA_UNKNOWN:
    274                 default: {
    275                     phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier);
    276                     break;
    277                 }
    278             }
    279         }
    280         return phone;
    281     }
    282 
    283     public static Phone getGsmPhone() {
    284         int phoneId = SubscriptionController.getInstance().getPhoneId(getDefaultSubscription());
    285         if (phoneId < 0 || phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
    286             phoneId = 0;
    287         }
    288         return getGsmPhone(phoneId);
    289     }
    290 
    291     /**
    292      * Makes a {@link SipPhone} object.
    293      * @param sipUri the local SIP URI the phone runs on
    294      * @return the {@code SipPhone} object or null if the SIP URI is not valid
    295      */
    296     public static SipPhone makeSipPhone(String sipUri) {
    297         return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier);
    298     }
    299 
    300     /* Sets the default subscription. If only one phone instance is active that
    301      * subscription is set as default subscription. If both phone instances
    302      * are active the first instance "0" is set as default subscription
    303      */
    304     public static void setDefaultSubscription(int subId) {
    305         SystemProperties.set(PROPERTY_DEFAULT_SUBSCRIPTION, Integer.toString(subId));
    306         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
    307 
    308         synchronized (sLockProxyPhones) {
    309             // Set the default phone in base class
    310             if (phoneId >= 0 && phoneId < sProxyPhones.length) {
    311                 sProxyPhone = sProxyPhones[phoneId];
    312                 sCommandsInterface = sCommandsInterfaces[phoneId];
    313                 sMadeDefaults = true;
    314             }
    315         }
    316 
    317         // Update MCC MNC device configuration information
    318         String defaultMccMnc = TelephonyManager.getDefault().getSimOperator(phoneId);
    319         Rlog.d(LOG_TAG, "update mccmnc=" + defaultMccMnc);
    320         MccTable.updateMccMncConfiguration(sContext, defaultMccMnc, false);
    321 
    322         // Broadcast an Intent for default sub change
    323         Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
    324         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    325         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
    326         Rlog.d(LOG_TAG, "setDefaultSubscription : " + subId
    327                 + " Broadcasting Default Subscription Changed...");
    328         sContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    329     }
    330 
    331     /**
    332      * Returns the preferred network type that should be set in the modem.
    333      *
    334      * @param context The current {@link Context}.
    335      * @return the preferred network mode that should be set.
    336      */
    337     // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController ..
    338     public static int calculatePreferredNetworkType(Context context) {
    339         int preferredNetworkType = RILConstants.PREFERRED_NETWORK_MODE;
    340         if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
    341             preferredNetworkType = Phone.NT_MODE_GLOBAL;
    342         }
    343         int networkType = Settings.Global.getInt(context.getContentResolver(),
    344                 Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkType);
    345         return networkType;
    346     }
    347 
    348     /* Gets the default subscription */
    349     public static long getDefaultSubscription() {
    350         return SubscriptionController.getInstance().getDefaultSubId();
    351     }
    352 
    353     /* Gets User preferred Voice subscription setting*/
    354     public static int getVoiceSubscription() {
    355         int subId = 0;
    356 
    357         try {
    358             subId = Settings.Global.getInt(sContext.getContentResolver(),
    359                     Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
    360         } catch (SettingNotFoundException snfe) {
    361             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Voice Call Values");
    362         }
    363 
    364         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
    365         // Set subscription to 0 if current subscription is invalid.
    366         // Ex: multisim.config property is TSTS and subscription is 2.
    367         // If user is trying to set multisim.config to DSDS and reboots
    368         // in this case index 2 is invalid so need to set to 0.
    369         if (phoneId < 0 || phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
    370             Rlog.i(LOG_TAG, "Subscription is invalid..." + subId + " Set to 0");
    371             subId = 0;
    372             setVoiceSubscription(subId);
    373         }
    374 
    375         return subId;
    376     }
    377 
    378     /* Returns User Prompt property,  enabed or not */
    379     public static boolean isPromptEnabled() {
    380         boolean prompt = false;
    381         int value = 0;
    382         try {
    383             value = Settings.Global.getInt(sContext.getContentResolver(),
    384                     Settings.Global.MULTI_SIM_VOICE_PROMPT);
    385         } catch (SettingNotFoundException snfe) {
    386             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Voice Prompt Values");
    387         }
    388         prompt = (value == 0) ? false : true ;
    389         Rlog.d(LOG_TAG, "Prompt option:" + prompt);
    390 
    391        return prompt;
    392     }
    393 
    394     /*Sets User Prompt property,  enabed or not */
    395     public static void setPromptEnabled(boolean enabled) {
    396         int value = (enabled == false) ? 0 : 1;
    397         Settings.Global.putInt(sContext.getContentResolver(),
    398                 Settings.Global.MULTI_SIM_VOICE_PROMPT, value);
    399         Rlog.d(LOG_TAG, "setVoicePromptOption to " + enabled);
    400     }
    401 
    402     /* Returns User SMS Prompt property,  enabled or not */
    403     public static boolean isSMSPromptEnabled() {
    404         boolean prompt = false;
    405         int value = 0;
    406         try {
    407             value = Settings.Global.getInt(sContext.getContentResolver(),
    408                     Settings.Global.MULTI_SIM_SMS_PROMPT);
    409         } catch (SettingNotFoundException snfe) {
    410             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Prompt Values");
    411         }
    412         prompt = (value == 0) ? false : true ;
    413         Rlog.d(LOG_TAG, "SMS Prompt option:" + prompt);
    414 
    415        return prompt;
    416     }
    417 
    418     /*Sets User SMS Prompt property,  enable or not */
    419     public static void setSMSPromptEnabled(boolean enabled) {
    420         int value = (enabled == false) ? 0 : 1;
    421         Settings.Global.putInt(sContext.getContentResolver(),
    422                 Settings.Global.MULTI_SIM_SMS_PROMPT, value);
    423         Rlog.d(LOG_TAG, "setSMSPromptOption to " + enabled);
    424     }
    425 
    426     /* Gets User preferred Data subscription setting*/
    427     public static long getDataSubscription() {
    428         long subId = 1;
    429 
    430         try {
    431             subId = Settings.Global.getLong(sContext.getContentResolver(),
    432                     Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION);
    433         } catch (SettingNotFoundException snfe) {
    434             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Data Call Values");
    435         }
    436 
    437         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
    438         if (phoneId < 0 || phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
    439             subId = 1;
    440             Rlog.i(LOG_TAG, "Subscription is invalid..." + subId + " Set to 0");
    441             setDataSubscription(subId);
    442         }
    443 
    444         return subId;
    445     }
    446 
    447     /* Gets User preferred SMS subscription setting*/
    448     public static int getSMSSubscription() {
    449         int subId = 0;
    450         try {
    451             subId = Settings.Global.getInt(sContext.getContentResolver(),
    452                     Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION);
    453         } catch (SettingNotFoundException snfe) {
    454             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Values");
    455         }
    456 
    457         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
    458         if (phoneId < 0 || phoneId >= TelephonyManager.getDefault().getPhoneCount()) {
    459             Rlog.i(LOG_TAG, "Subscription is invalid..." + subId + " Set to 0");
    460             subId = 0;
    461             setSMSSubscription(subId);
    462         }
    463 
    464         return subId;
    465     }
    466 
    467     static public void setVoiceSubscription(int subId) {
    468         Settings.Global.putInt(sContext.getContentResolver(),
    469                 Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, subId);
    470         Rlog.d(LOG_TAG, "setVoiceSubscription : " + subId);
    471     }
    472 
    473     static public void setDataSubscription(long subId) {
    474         boolean enabled;
    475 
    476         Settings.Global.putLong(sContext.getContentResolver(),
    477                 Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, subId);
    478         Rlog.d(LOG_TAG, "setDataSubscription: " + subId);
    479 
    480         // Update the current mobile data flag
    481         enabled = Settings.Global.getInt(sContext.getContentResolver(),
    482                 Settings.Global.MOBILE_DATA + subId, 0) != 0;
    483         Settings.Global.putInt(sContext.getContentResolver(),
    484                 Settings.Global.MOBILE_DATA, enabled ? 1 : 0);
    485         Rlog.d(LOG_TAG, "set mobile_data: " + enabled);
    486 
    487         // Update the current data roaming flag
    488         enabled = Settings.Global.getInt(sContext.getContentResolver(),
    489                 Settings.Global.DATA_ROAMING + subId, 0) != 0;
    490         Settings.Global.putInt(sContext.getContentResolver(),
    491                 Settings.Global.DATA_ROAMING, enabled ? 1 : 0);
    492         Rlog.d(LOG_TAG, "set data_roaming: " + enabled);
    493     }
    494 
    495     static public void setSMSSubscription(int subId) {
    496         Settings.Global.putInt(sContext.getContentResolver(),
    497                 Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, subId);
    498 
    499         Intent intent = new Intent("com.android.mms.transaction.SEND_MESSAGE");
    500         sContext.sendBroadcast(intent);
    501 
    502         // Change occured in SMS preferred sub, update the default
    503         // SMS interface Manager object with the new SMS preferred subscription.
    504         Rlog.d(LOG_TAG, "setSMSSubscription : " + subId);
    505     }
    506 
    507     /**
    508      * Makes a {@link ImsPhone} object.
    509      * @return the {@code ImsPhone} object or null if the exception occured
    510      */
    511     public static ImsPhone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone) {
    512         return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone);
    513     }
    514 }
    515