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