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