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