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