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.Context;
20import android.net.LocalServerSocket;
21import android.os.Looper;
22import android.provider.Settings;
23import android.telephony.TelephonyManager;
24import android.util.Log;
25import android.os.SystemProperties;
26
27import com.android.internal.telephony.cdma.CDMAPhone;
28import com.android.internal.telephony.cdma.CDMALTEPhone;
29import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
30import com.android.internal.telephony.gsm.GSMPhone;
31import com.android.internal.telephony.sip.SipPhone;
32import com.android.internal.telephony.sip.SipPhoneFactory;
33import com.android.internal.telephony.uicc.UiccController;
34
35/**
36 * {@hide}
37 */
38public class PhoneFactory {
39    static final String LOG_TAG = "PHONE";
40    static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000;
41    static final int SOCKET_OPEN_MAX_RETRY = 3;
42
43    //***** Class Variables
44
45    static private Phone sProxyPhone = null;
46    static private CommandsInterface sCommandsInterface = null;
47
48    static private boolean sMadeDefaults = false;
49    static private PhoneNotifier sPhoneNotifier;
50    static private Looper sLooper;
51    static private Context sContext;
52
53    static final int preferredCdmaSubscription =
54                         CdmaSubscriptionSourceManager.PREFERRED_CDMA_SUBSCRIPTION;
55
56    //***** Class Methods
57
58    public static void makeDefaultPhones(Context context) {
59        makeDefaultPhone(context);
60    }
61
62    /**
63     * FIXME replace this with some other way of making these
64     * instances
65     */
66    public static void makeDefaultPhone(Context context) {
67        synchronized(Phone.class) {
68            if (!sMadeDefaults) {
69                sLooper = Looper.myLooper();
70                sContext = context;
71
72                if (sLooper == null) {
73                    throw new RuntimeException(
74                        "PhoneFactory.makeDefaultPhone must be called from Looper thread");
75                }
76
77                int retryCount = 0;
78                for(;;) {
79                    boolean hasException = false;
80                    retryCount ++;
81
82                    try {
83                        // use UNIX domain socket to
84                        // prevent subsequent initialization
85                        new LocalServerSocket("com.android.internal.telephony");
86                    } catch (java.io.IOException ex) {
87                        hasException = true;
88                    }
89
90                    if ( !hasException ) {
91                        break;
92                    } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
93                        throw new RuntimeException("PhoneFactory probably already running");
94                    } else {
95                        try {
96                            Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
97                        } catch (InterruptedException er) {
98                        }
99                    }
100                }
101
102                sPhoneNotifier = new DefaultPhoneNotifier();
103
104                // Get preferred network mode
105                int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
106                if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
107                    preferredNetworkMode = Phone.NT_MODE_GLOBAL;
108                }
109                int networkMode = Settings.Global.getInt(context.getContentResolver(),
110                        Settings.Global.PREFERRED_NETWORK_MODE, preferredNetworkMode);
111                Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));
112
113                // Get cdmaSubscription
114                // TODO: Change when the ril will provides a way to know at runtime
115                //       the configuration, bug 4202572. And the ril issues the
116                //       RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, bug 4295439.
117                int cdmaSubscription;
118                int lteOnCdma = TelephonyManager.getLteOnCdmaModeStatic();
119                switch (lteOnCdma) {
120                    case PhoneConstants.LTE_ON_CDMA_FALSE:
121                        cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV;
122                        Log.i(LOG_TAG, "lteOnCdma is 0 use SUBSCRIPTION_FROM_NV");
123                        break;
124                    case PhoneConstants.LTE_ON_CDMA_TRUE:
125                        cdmaSubscription = CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_RUIM;
126                        Log.i(LOG_TAG, "lteOnCdma is 1 use SUBSCRIPTION_FROM_RUIM");
127                        break;
128                    case PhoneConstants.LTE_ON_CDMA_UNKNOWN:
129                    default:
130                        //Get cdmaSubscription mode from Settings.System
131                        cdmaSubscription = Settings.Global.getInt(context.getContentResolver(),
132                                Settings.Global.PREFERRED_CDMA_SUBSCRIPTION,
133                                preferredCdmaSubscription);
134                        Log.i(LOG_TAG, "lteOnCdma not set, using PREFERRED_CDMA_SUBSCRIPTION");
135                        break;
136                }
137                Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
138
139                //reads the system properties and makes commandsinterface
140                sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
141
142                // Instantiate UiccController so that all other classes can just call getInstance()
143                UiccController.make(context, sCommandsInterface);
144
145                int phoneType = TelephonyManager.getPhoneType(networkMode);
146                if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
147                    Log.i(LOG_TAG, "Creating GSMPhone");
148                    sProxyPhone = new PhoneProxy(new GSMPhone(context,
149                            sCommandsInterface, sPhoneNotifier));
150                } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
151                    switch (TelephonyManager.getLteOnCdmaModeStatic()) {
152                        case PhoneConstants.LTE_ON_CDMA_TRUE:
153                            Log.i(LOG_TAG, "Creating CDMALTEPhone");
154                            sProxyPhone = new PhoneProxy(new CDMALTEPhone(context,
155                                sCommandsInterface, sPhoneNotifier));
156                            break;
157                        case PhoneConstants.LTE_ON_CDMA_FALSE:
158                        default:
159                            Log.i(LOG_TAG, "Creating CDMAPhone");
160                            sProxyPhone = new PhoneProxy(new CDMAPhone(context,
161                                    sCommandsInterface, sPhoneNotifier));
162                            break;
163                    }
164                }
165
166                sMadeDefaults = true;
167            }
168        }
169    }
170
171    public static Phone getDefaultPhone() {
172        if (sLooper != Looper.myLooper()) {
173            throw new RuntimeException(
174                "PhoneFactory.getDefaultPhone must be called from Looper thread");
175        }
176
177        if (!sMadeDefaults) {
178            throw new IllegalStateException("Default phones haven't been made yet!");
179        }
180       return sProxyPhone;
181    }
182
183    public static Phone getCdmaPhone() {
184        Phone phone;
185        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
186            switch (TelephonyManager.getLteOnCdmaModeStatic()) {
187                case PhoneConstants.LTE_ON_CDMA_TRUE: {
188                    phone = new CDMALTEPhone(sContext, sCommandsInterface, sPhoneNotifier);
189                    break;
190                }
191                case PhoneConstants.LTE_ON_CDMA_FALSE:
192                case PhoneConstants.LTE_ON_CDMA_UNKNOWN:
193                default: {
194                    phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier);
195                    break;
196                }
197            }
198        }
199        return phone;
200    }
201
202    public static Phone getGsmPhone() {
203        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
204            Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier);
205            return phone;
206        }
207    }
208
209    /**
210     * Makes a {@link SipPhone} object.
211     * @param sipUri the local SIP URI the phone runs on
212     * @return the {@code SipPhone} object or null if the SIP URI is not valid
213     */
214    public static SipPhone makeSipPhone(String sipUri) {
215        return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier);
216    }
217}
218