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 import android.util.LocalLog;
     33 
     34 import com.android.internal.telephony.cdma.CDMALTEPhone;
     35 import com.android.internal.telephony.cdma.CDMAPhone;
     36 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
     37 import com.android.internal.telephony.dataconnection.DctController;
     38 import com.android.internal.telephony.gsm.GSMPhone;
     39 import com.android.internal.telephony.SubscriptionInfoUpdater;
     40 import com.android.internal.telephony.imsphone.ImsPhone;
     41 import com.android.internal.telephony.imsphone.ImsPhoneFactory;
     42 import com.android.internal.telephony.sip.SipPhone;
     43 import com.android.internal.telephony.sip.SipPhoneFactory;
     44 import com.android.internal.telephony.uicc.IccCardProxy;
     45 import com.android.internal.telephony.uicc.UiccController;
     46 import com.android.internal.util.IndentingPrintWriter;
     47 
     48 import java.io.FileDescriptor;
     49 import java.io.PrintWriter;
     50 import java.util.HashMap;
     51 
     52 /**
     53  * {@hide}
     54  */
     55 public class PhoneFactory {
     56     static final String LOG_TAG = "PhoneFactory";
     57     static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000;
     58     static final int SOCKET_OPEN_MAX_RETRY = 3;
     59     static final boolean DBG = false;
     60 
     61     //***** Class Variables
     62 
     63     // lock sLockProxyPhones protects both sProxyPhones and sProxyPhone
     64     final static Object sLockProxyPhones = new Object();
     65     static private PhoneProxy[] sProxyPhones = null;
     66     static private PhoneProxy sProxyPhone = null;
     67 
     68     static private CommandsInterface[] sCommandsInterfaces = null;
     69 
     70     static private ProxyController mProxyController;
     71     static private UiccController mUiccController;
     72 
     73     static private CommandsInterface sCommandsInterface = null;
     74     static private SubscriptionInfoUpdater sSubInfoRecordUpdater = null;
     75 
     76     static private boolean sMadeDefaults = false;
     77     static private PhoneNotifier sPhoneNotifier;
     78     static private Context sContext;
     79 
     80     static private final HashMap<String, LocalLog>sLocalLogs = new HashMap<String, LocalLog>();
     81 
     82     //***** Class Methods
     83 
     84     public static void makeDefaultPhones(Context context) {
     85         makeDefaultPhone(context);
     86     }
     87 
     88     /**
     89      * FIXME replace this with some other way of making these
     90      * instances
     91      */
     92     public static void makeDefaultPhone(Context context) {
     93         synchronized (sLockProxyPhones) {
     94             if (!sMadeDefaults) {
     95                 sContext = context;
     96 
     97                 // create the telephony device controller.
     98                 TelephonyDevController.create();
     99 
    100                 int retryCount = 0;
    101                 for(;;) {
    102                     boolean hasException = false;
    103                     retryCount ++;
    104 
    105                     try {
    106                         // use UNIX domain socket to
    107                         // prevent subsequent initialization
    108                         new LocalServerSocket("com.android.internal.telephony");
    109                     } catch (java.io.IOException ex) {
    110                         hasException = true;
    111                     }
    112 
    113                     if ( !hasException ) {
    114                         break;
    115                     } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
    116                         throw new RuntimeException("PhoneFactory probably already running");
    117                     } else {
    118                         try {
    119                             Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
    120                         } catch (InterruptedException er) {
    121                         }
    122                     }
    123                 }
    124 
    125                 sPhoneNotifier = new DefaultPhoneNotifier();
    126 
    127                 int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
    128                 Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
    129 
    130                 /* In case of multi SIM mode two instances of PhoneProxy, RIL are created,
    131                    where as in single SIM mode only instance. isMultiSimEnabled() function checks
    132                    whether it is single SIM or multi SIM mode */
    133                 int numPhones = TelephonyManager.getDefault().getPhoneCount();
    134                 int[] networkModes = new int[numPhones];
    135                 sProxyPhones = new PhoneProxy[numPhones];
    136                 sCommandsInterfaces = new RIL[numPhones];
    137 
    138                 for (int i = 0; i < numPhones; i++) {
    139                     // reads the system properties and makes commandsinterface
    140                     // Get preferred network type.
    141                     networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
    142 
    143                     Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
    144                     sCommandsInterfaces[i] = new RIL(context, networkModes[i],
    145                             cdmaSubscription, i);
    146                 }
    147                 Rlog.i(LOG_TAG, "Creating SubscriptionController");
    148                 SubscriptionController.init(context, sCommandsInterfaces);
    149 
    150                 // Instantiate UiccController so that all other classes can just
    151                 // call getInstance()
    152                 mUiccController = UiccController.make(context, sCommandsInterfaces);
    153 
    154                 for (int i = 0; i < numPhones; i++) {
    155                     PhoneBase phone = null;
    156                     int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
    157                     if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
    158                         phone = new GSMPhone(context,
    159                                 sCommandsInterfaces[i], sPhoneNotifier, i);
    160                         phone.startMonitoringImsService();
    161                     } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
    162                         phone = new CDMALTEPhone(context,
    163                                 sCommandsInterfaces[i], sPhoneNotifier, i);
    164                         phone.startMonitoringImsService();
    165                     }
    166                     Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
    167 
    168                     sProxyPhones[i] = new PhoneProxy(phone);
    169                 }
    170                 mProxyController = ProxyController.getInstance(context, sProxyPhones,
    171                         mUiccController, sCommandsInterfaces);
    172 
    173                 // Set the default phone in base class.
    174                 // FIXME: This is a first best guess at what the defaults will be. It
    175                 // FIXME: needs to be done in a more controlled manner in the future.
    176                 sProxyPhone = sProxyPhones[0];
    177                 sCommandsInterface = sCommandsInterfaces[0];
    178 
    179                 // Ensure that we have a default SMS app. Requesting the app with
    180                 // updateIfNeeded set to true is enough to configure a default SMS app.
    181                 ComponentName componentName =
    182                         SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */);
    183                 String packageName = "NONE";
    184                 if (componentName != null) {
    185                     packageName = componentName.getPackageName();
    186                 }
    187                 Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);
    188 
    189                 // Set up monitor to watch for changes to SMS packages
    190                 SmsApplication.initSmsPackageMonitor(context);
    191 
    192                 sMadeDefaults = true;
    193 
    194                 Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
    195                 sSubInfoRecordUpdater = new SubscriptionInfoUpdater(context,
    196                         sProxyPhones, sCommandsInterfaces);
    197                 SubscriptionController.getInstance().updatePhonesAvailability(sProxyPhones);
    198             }
    199         }
    200     }
    201 
    202     public static Phone getCdmaPhone(int phoneId) {
    203         Phone phone;
    204         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    205             phone = new CDMALTEPhone(sContext, sCommandsInterfaces[phoneId],
    206                     sPhoneNotifier, phoneId);
    207         }
    208         return phone;
    209     }
    210 
    211     public static Phone getGsmPhone(int phoneId) {
    212         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
    213             Phone phone = new GSMPhone(sContext, sCommandsInterfaces[phoneId],
    214                     sPhoneNotifier, phoneId);
    215             return phone;
    216         }
    217     }
    218 
    219     public static Phone getDefaultPhone() {
    220         synchronized (sLockProxyPhones) {
    221             if (!sMadeDefaults) {
    222                 throw new IllegalStateException("Default phones haven't been made yet!");
    223             }
    224             return sProxyPhone;
    225         }
    226     }
    227 
    228     public static Phone getPhone(int phoneId) {
    229         Phone phone;
    230         String dbgInfo = "";
    231 
    232         synchronized (sLockProxyPhones) {
    233             if (!sMadeDefaults) {
    234                 throw new IllegalStateException("Default phones haven't been made yet!");
    235                 // CAF_MSIM FIXME need to introduce default phone id ?
    236             } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
    237                 if (DBG) dbgInfo = "phoneId == DEFAULT_PHONE_ID return sProxyPhone";
    238                 phone = sProxyPhone;
    239             } else {
    240                 if (DBG) dbgInfo = "phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId]";
    241                 phone = (((phoneId >= 0)
    242                                 && (phoneId < TelephonyManager.getDefault().getPhoneCount()))
    243                         ? sProxyPhones[phoneId] : null);
    244             }
    245             if (DBG) {
    246                 Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId +
    247                         " phone=" + phone);
    248             }
    249             return phone;
    250         }
    251     }
    252 
    253     public static Phone[] getPhones() {
    254         synchronized (sLockProxyPhones) {
    255             if (!sMadeDefaults) {
    256                 throw new IllegalStateException("Default phones haven't been made yet!");
    257             }
    258             return sProxyPhones;
    259         }
    260     }
    261 
    262     /**
    263      * Makes a {@link SipPhone} object.
    264      * @param sipUri the local SIP URI the phone runs on
    265      * @return the {@code SipPhone} object or null if the SIP URI is not valid
    266      */
    267     public static SipPhone makeSipPhone(String sipUri) {
    268         return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier);
    269     }
    270 
    271     /* Sets the default subscription. If only one phone instance is active that
    272      * subscription is set as default subscription. If both phone instances
    273      * are active the first instance "0" is set as default subscription
    274      */
    275     public static void setDefaultSubscription(int subId) {
    276         SystemProperties.set(PROPERTY_DEFAULT_SUBSCRIPTION, Integer.toString(subId));
    277         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
    278 
    279         synchronized (sLockProxyPhones) {
    280             // Set the default phone in base class
    281             if (phoneId >= 0 && phoneId < sProxyPhones.length) {
    282                 sProxyPhone = sProxyPhones[phoneId];
    283                 sCommandsInterface = sCommandsInterfaces[phoneId];
    284                 sMadeDefaults = true;
    285             }
    286         }
    287 
    288         // Update MCC MNC device configuration information
    289         String defaultMccMnc = TelephonyManager.getDefault().getSimOperatorNumericForPhone(phoneId);
    290         if (DBG) Rlog.d(LOG_TAG, "update mccmnc=" + defaultMccMnc);
    291         MccTable.updateMccMncConfiguration(sContext, defaultMccMnc, false);
    292 
    293         // Broadcast an Intent for default sub change
    294         Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
    295         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    296         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
    297         Rlog.d(LOG_TAG, "setDefaultSubscription : " + subId
    298                 + " Broadcasting Default Subscription Changed...");
    299         sContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    300     }
    301 
    302     /**
    303      * Returns the preferred network type that should be set in the modem.
    304      *
    305      * @param context The current {@link Context}.
    306      * @return the preferred network mode that should be set.
    307      */
    308     // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController ..
    309     public static int calculatePreferredNetworkType(Context context, int phoneSubId) {
    310         int networkType = android.provider.Settings.Global.getInt(context.getContentResolver(),
    311                 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
    312                 RILConstants.PREFERRED_NETWORK_MODE);
    313         Rlog.d(LOG_TAG, "calculatePreferredNetworkType: phoneSubId = " + phoneSubId +
    314                 " networkType = " + networkType);
    315         return networkType;
    316     }
    317 
    318     /* Gets the default subscription */
    319     public static int getDefaultSubscription() {
    320         return SubscriptionController.getInstance().getDefaultSubId();
    321     }
    322 
    323     /* Gets User preferred Voice subscription setting*/
    324     public static int getVoiceSubscription() {
    325         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    326 
    327         try {
    328             subId = Settings.Global.getInt(sContext.getContentResolver(),
    329                     Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
    330         } catch (SettingNotFoundException snfe) {
    331             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Voice Call Values");
    332         }
    333 
    334         return subId;
    335     }
    336 
    337     /* Returns User Prompt property,  enabed or not */
    338     public static boolean isPromptEnabled() {
    339         boolean prompt = false;
    340         int value = 0;
    341         try {
    342             value = Settings.Global.getInt(sContext.getContentResolver(),
    343                     Settings.Global.MULTI_SIM_VOICE_PROMPT);
    344         } catch (SettingNotFoundException snfe) {
    345             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Voice Prompt Values");
    346         }
    347         prompt = (value == 0) ? false : true ;
    348         Rlog.d(LOG_TAG, "Prompt option:" + prompt);
    349 
    350        return prompt;
    351     }
    352 
    353     /*Sets User Prompt property,  enabed or not */
    354     public static void setPromptEnabled(boolean enabled) {
    355         int value = (enabled == false) ? 0 : 1;
    356         Settings.Global.putInt(sContext.getContentResolver(),
    357                 Settings.Global.MULTI_SIM_VOICE_PROMPT, value);
    358         Rlog.d(LOG_TAG, "setVoicePromptOption to " + enabled);
    359     }
    360 
    361     /* Returns User SMS Prompt property,  enabled or not */
    362     public static boolean isSMSPromptEnabled() {
    363         boolean prompt = false;
    364         int value = 0;
    365         try {
    366             value = Settings.Global.getInt(sContext.getContentResolver(),
    367                     Settings.Global.MULTI_SIM_SMS_PROMPT);
    368         } catch (SettingNotFoundException snfe) {
    369             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Prompt Values");
    370         }
    371         prompt = (value == 0) ? false : true ;
    372         Rlog.d(LOG_TAG, "SMS Prompt option:" + prompt);
    373 
    374        return prompt;
    375     }
    376 
    377     /*Sets User SMS Prompt property,  enable or not */
    378     public static void setSMSPromptEnabled(boolean enabled) {
    379         int value = (enabled == false) ? 0 : 1;
    380         Settings.Global.putInt(sContext.getContentResolver(),
    381                 Settings.Global.MULTI_SIM_SMS_PROMPT, value);
    382         Rlog.d(LOG_TAG, "setSMSPromptOption to " + enabled);
    383     }
    384 
    385     /* Gets User preferred Data subscription setting*/
    386     public static long getDataSubscription() {
    387         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    388 
    389         try {
    390             subId = Settings.Global.getInt(sContext.getContentResolver(),
    391                     Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION);
    392         } catch (SettingNotFoundException snfe) {
    393             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Data Call Values");
    394         }
    395 
    396         return subId;
    397     }
    398 
    399     /* Gets User preferred SMS subscription setting*/
    400     public static int getSMSSubscription() {
    401         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    402         try {
    403             subId = Settings.Global.getInt(sContext.getContentResolver(),
    404                     Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION);
    405         } catch (SettingNotFoundException snfe) {
    406             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Values");
    407         }
    408 
    409         return subId;
    410     }
    411 
    412     /**
    413      * Makes a {@link ImsPhone} object.
    414      * @return the {@code ImsPhone} object or null if the exception occured
    415      */
    416     public static ImsPhone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone) {
    417         return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone);
    418     }
    419 
    420     /**
    421      * Adds a local log category.
    422      *
    423      * Only used within the telephony process.  Use localLog to add log entries.
    424      *
    425      * TODO - is there a better way to do this?  Think about design when we have a minute.
    426      *
    427      * @param key the name of the category - will be the header in the service dump.
    428      * @param size the number of lines to maintain in this category
    429      */
    430     public static void addLocalLog(String key, int size) {
    431         synchronized(sLocalLogs) {
    432             if (sLocalLogs.containsKey(key)) {
    433                 throw new IllegalArgumentException("key " + key + " already present");
    434             }
    435             sLocalLogs.put(key, new LocalLog(size));
    436         }
    437     }
    438 
    439     /**
    440      * Add a line to the named Local Log.
    441      *
    442      * This will appear in the TelephonyDebugService dump.
    443      *
    444      * @param key the name of the log category to put this in.  Must be created
    445      *            via addLocalLog.
    446      * @param log the string to add to the log.
    447      */
    448     public static void localLog(String key, String log) {
    449         synchronized(sLocalLogs) {
    450             if (sLocalLogs.containsKey(key) == false) {
    451                 throw new IllegalArgumentException("key " + key + " not found");
    452             }
    453             sLocalLogs.get(key).log(log);
    454         }
    455     }
    456 
    457     public static void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    458         pw.println("PhoneFactory:");
    459         PhoneProxy [] phones = (PhoneProxy[])PhoneFactory.getPhones();
    460         int i = -1;
    461         for(PhoneProxy phoneProxy : phones) {
    462             PhoneBase phoneBase;
    463             i += 1;
    464 
    465             try {
    466                 phoneBase = (PhoneBase)phoneProxy.getActivePhone();
    467                 phoneBase.dump(fd, pw, args);
    468             } catch (Exception e) {
    469                 pw.println("Telephony DebugService: Could not get Phone[" + i + "] e=" + e);
    470                 continue;
    471             }
    472 
    473             pw.flush();
    474             pw.println("++++++++++++++++++++++++++++++++");
    475 
    476             try {
    477                 ((IccCardProxy)phoneProxy.getIccCard()).dump(fd, pw, args);
    478             } catch (Exception e) {
    479                 e.printStackTrace();
    480             }
    481             pw.flush();
    482             pw.println("++++++++++++++++++++++++++++++++");
    483         }
    484 
    485         try {
    486             DctController.getInstance().dump(fd, pw, args);
    487         } catch (Exception e) {
    488             e.printStackTrace();
    489         }
    490 
    491         try {
    492             mUiccController.dump(fd, pw, args);
    493         } catch (Exception e) {
    494             e.printStackTrace();
    495         }
    496         pw.flush();
    497         pw.println("++++++++++++++++++++++++++++++++");
    498 
    499         try {
    500             SubscriptionController.getInstance().dump(fd, pw, args);
    501         } catch (Exception e) {
    502             e.printStackTrace();
    503         }
    504         pw.flush();
    505         pw.println("++++++++++++++++++++++++++++++++");
    506 
    507         try {
    508             sSubInfoRecordUpdater.dump(fd, pw, args);
    509         } catch (Exception e) {
    510             e.printStackTrace();
    511         }
    512         pw.flush();
    513 
    514         pw.println("++++++++++++++++++++++++++++++++");
    515         synchronized (sLocalLogs) {
    516             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
    517             for (String key : sLocalLogs.keySet()) {
    518                 ipw.println(key);
    519                 ipw.increaseIndent();
    520                 sLocalLogs.get(key).dump(fd, ipw, args);
    521                 ipw.decreaseIndent();
    522             }
    523             ipw.flush();
    524         }
    525     }
    526 }
    527