987793467bf2d8ba450213bde6106673db889519
[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
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
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      */
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                         phone.startMonitoringImsService();
155                     } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
156                         phone = new CDMALTEPhone(context,
157                                 sCommandsInterfaces[i], sPhoneNotifier, i);
158                         phone.startMonitoringImsService();
159                     }
160                     Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
161
162                     sProxyPhones[i] = new PhoneProxy(phone);
163                 }
164                 mProxyController = ProxyController.getInstance(context, sProxyPhones,
165                         mUiccController, sCommandsInterfaces);
166
167                 // Set the default phone in base class.
168                 // FIXME: This is a first best guess at what the defaults will be. It
169                 // FIXME: needs to be done in a more controlled manner in the future.
170                 sProxyPhone = sProxyPhones[0];
171                 sCommandsInterface = sCommandsInterfaces[0];
172
173                 // Ensure that we have a default SMS app. Requesting the app with
174                 // updateIfNeeded set to true is enough to configure a default SMS app.
175                 ComponentName componentName =
176                         SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */);
177                 String packageName = "NONE";
178                 if (componentName != null) {
179                     packageName = componentName.getPackageName();
180                 }
181                 Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);
182
183                 // Set up monitor to watch for changes to SMS packages
184                 SmsApplication.initSmsPackageMonitor(context);
185
186                 sMadeDefaults = true;
187
188                 Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
189                 sSubInfoRecordUpdater = new SubscriptionInfoUpdater(context,
190                         sProxyPhones, sCommandsInterfaces);
191                 SubscriptionController.getInstance().updatePhonesAvailability(sProxyPhones);
192             }
193         }
194     }
195
196     public static Phone getCdmaPhone(int phoneId) {
197         Phone phone;
198         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
199             phone = new CDMALTEPhone(sContext, sCommandsInterfaces[phoneId],
200                     sPhoneNotifier, phoneId);
201         }
202         return phone;
203     }
204
205     public static Phone getGsmPhone(int phoneId) {
206         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
207             Phone phone = new GSMPhone(sContext, sCommandsInterfaces[phoneId],
208                     sPhoneNotifier, phoneId);
209             return phone;
210         }
211     }
212
213     public static Phone getDefaultPhone() {
214         synchronized (sLockProxyPhones) {
215             if (!sMadeDefaults) {
216                 throw new IllegalStateException("Default phones haven't been made yet!");
217             }
218             return sProxyPhone;
219         }
220     }
221
222     public static Phone getPhone(int phoneId) {
223         Phone phone;
224         String dbgInfo = "";
225
226         synchronized (sLockProxyPhones) {
227             if (!sMadeDefaults) {
228                 throw new IllegalStateException("Default phones haven't been made yet!");
229                 // CAF_MSIM FIXME need to introduce default phone id ?
230             } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
231                 dbgInfo = "phoneId == DEFAULT_PHONE_ID return sProxyPhone";
232                 phone = sProxyPhone;
233             } else {
234                 dbgInfo = "phoneId != DEFAULT_PHONE_ID return sProxyPhones[phoneId]";
235                 phone = (((phoneId >= 0)
236                                 && (phoneId < TelephonyManager.getDefault().getPhoneCount()))
237                         ? sProxyPhones[phoneId] : null);
238             }
239             Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId + " phone=" + phone);
240             return phone;
241         }
242     }
243
244     public static Phone[] getPhones() {
245         synchronized (sLockProxyPhones) {
246             if (!sMadeDefaults) {
247                 throw new IllegalStateException("Default phones haven't been made yet!");
248             }
249             return sProxyPhones;
250         }
251     }
252
253     /**
254      * Makes a {@link SipPhone} object.
255      * @param sipUri the local SIP URI the phone runs on
256      * @return the {@code SipPhone} object or null if the SIP URI is not valid
257      */
258     public static SipPhone makeSipPhone(String sipUri) {
259         return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier);
260     }
261
262     /* Sets the default subscription. If only one phone instance is active that
263      * subscription is set as default subscription. If both phone instances
264      * are active the first instance "0" is set as default subscription
265      */
266     public static void setDefaultSubscription(int subId) {
267         SystemProperties.set(PROPERTY_DEFAULT_SUBSCRIPTION, Integer.toString(subId));
268         int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
269
270         synchronized (sLockProxyPhones) {
271             // Set the default phone in base class
272             if (phoneId >= 0 && phoneId < sProxyPhones.length) {
273                 sProxyPhone = sProxyPhones[phoneId];
274                 sCommandsInterface = sCommandsInterfaces[phoneId];
275                 sMadeDefaults = true;
276             }
277         }
278
279         // Update MCC MNC device configuration information
280         String defaultMccMnc = TelephonyManager.getDefault().getSimOperatorNumericForPhone(phoneId);
281         Rlog.d(LOG_TAG, "update mccmnc=" + defaultMccMnc);
282         MccTable.updateMccMncConfiguration(sContext, defaultMccMnc, false);
283
284         // Broadcast an Intent for default sub change
285         Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
286         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
287         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
288         Rlog.d(LOG_TAG, "setDefaultSubscription : " + subId
289                 + " Broadcasting Default Subscription Changed...");
290         sContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
291     }
292
293     /**
294      * Returns the preferred network type that should be set in the modem.
295      *
296      * @param context The current {@link Context}.
297      * @return the preferred network mode that should be set.
298      */
299     // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController ..
300     public static int calculatePreferredNetworkType(Context context, int phoneSubId) {
301         int networkType = android.provider.Settings.Global.getInt(context.getContentResolver(),
302                 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId,
303                 RILConstants.PREFERRED_NETWORK_MODE);
304         Rlog.d(LOG_TAG, "calculatePreferredNetworkType: phoneSubId = " + phoneSubId +
305                 " networkType = " + networkType);
306         return networkType;
307     }
308
309     /* Gets the default subscription */
310     public static int getDefaultSubscription() {
311         return SubscriptionController.getInstance().getDefaultSubId();
312     }
313
314     /* Gets User preferred Voice subscription setting*/
315     public static int getVoiceSubscription() {
316         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
317
318         try {
319             subId = Settings.Global.getInt(sContext.getContentResolver(),
320                     Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
321         } catch (SettingNotFoundException snfe) {
322             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Voice Call Values");
323         }
324
325         return subId;
326     }
327
328     /* Returns User Prompt property,  enabed or not */
329     public static boolean isPromptEnabled() {
330         boolean prompt = false;
331         int value = 0;
332         try {
333             value = Settings.Global.getInt(sContext.getContentResolver(),
334                     Settings.Global.MULTI_SIM_VOICE_PROMPT);
335         } catch (SettingNotFoundException snfe) {
336             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Voice Prompt Values");
337         }
338         prompt = (value == 0) ? false : true ;
339         Rlog.d(LOG_TAG, "Prompt option:" + prompt);
340
341        return prompt;
342     }
343
344     /*Sets User Prompt property,  enabed or not */
345     public static void setPromptEnabled(boolean enabled) {
346         int value = (enabled == false) ? 0 : 1;
347         Settings.Global.putInt(sContext.getContentResolver(),
348                 Settings.Global.MULTI_SIM_VOICE_PROMPT, value);
349         Rlog.d(LOG_TAG, "setVoicePromptOption to " + enabled);
350     }
351
352     /* Returns User SMS Prompt property,  enabled or not */
353     public static boolean isSMSPromptEnabled() {
354         boolean prompt = false;
355         int value = 0;
356         try {
357             value = Settings.Global.getInt(sContext.getContentResolver(),
358                     Settings.Global.MULTI_SIM_SMS_PROMPT);
359         } catch (SettingNotFoundException snfe) {
360             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Prompt Values");
361         }
362         prompt = (value == 0) ? false : true ;
363         Rlog.d(LOG_TAG, "SMS Prompt option:" + prompt);
364
365        return prompt;
366     }
367
368     /*Sets User SMS Prompt property,  enable or not */
369     public static void setSMSPromptEnabled(boolean enabled) {
370         int value = (enabled == false) ? 0 : 1;
371         Settings.Global.putInt(sContext.getContentResolver(),
372                 Settings.Global.MULTI_SIM_SMS_PROMPT, value);
373         Rlog.d(LOG_TAG, "setSMSPromptOption to " + enabled);
374     }
375
376     /* Gets User preferred Data subscription setting*/
377     public static long getDataSubscription() {
378         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
379
380         try {
381             subId = Settings.Global.getInt(sContext.getContentResolver(),
382                     Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION);
383         } catch (SettingNotFoundException snfe) {
384             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim Data Call Values");
385         }
386
387         return subId;
388     }
389
390     /* Gets User preferred SMS subscription setting*/
391     public static int getSMSSubscription() {
392         int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
393         try {
394             subId = Settings.Global.getInt(sContext.getContentResolver(),
395                     Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION);
396         } catch (SettingNotFoundException snfe) {
397             Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Values");
398         }
399
400         return subId;
401     }
402
403     /**
404      * Makes a {@link ImsPhone} object.
405      * @return the {@code ImsPhone} object or null if the exception occured
406      */
407     public static ImsPhone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone) {
408         return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone);
409     }
410
411     public static void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
412         pw.println("PhoneFactory:");
413         PhoneProxy [] phones = (PhoneProxy[])PhoneFactory.getPhones();
414         int i = -1;
415         for(PhoneProxy phoneProxy : phones) {
416             PhoneBase phoneBase;
417             i += 1;
418
419             try {
420                 phoneBase = (PhoneBase)phoneProxy.getActivePhone();
421                 phoneBase.dump(fd, pw, args);
422             } catch (Exception e) {
423                 pw.println("Telephony DebugService: Could not get Phone[" + i + "] e=" + e);
424                 continue;
425             }
426
427             pw.flush();
428             pw.println("++++++++++++++++++++++++++++++++");
429
430             try {
431                 ((IccCardProxy)phoneProxy.getIccCard()).dump(fd, pw, args);
432             } catch (Exception e) {
433                 e.printStackTrace();
434             }
435             pw.flush();
436             pw.println("++++++++++++++++++++++++++++++++");
437         }
438
439         try {
440             DctController.getInstance().dump(fd, pw, args);
441         } catch (Exception e) {
442             e.printStackTrace();
443         }
444
445         try {
446             mUiccController.dump(fd, pw, args);
447         } catch (Exception e) {
448             e.printStackTrace();
449         }
450         pw.flush();
451         pw.println("++++++++++++++++++++++++++++++++");
452
453         try {
454             SubscriptionController.getInstance().dump(fd, pw, args);
455         } catch (Exception e) {
456             e.printStackTrace();
457         }
458         pw.flush();
459         pw.println("++++++++++++++++++++++++++++++++");
460
461         try {
462             sSubInfoRecordUpdater.dump(fd, pw, args);
463         } catch (Exception e) {
464             e.printStackTrace();
465         }
466         pw.flush();
467     }
468 }