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