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