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