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