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;
24
25import com.android.internal.telephony.cdma.CDMAPhone;
26import com.android.internal.telephony.gsm.GSMPhone;
27import com.android.internal.telephony.sip.SipPhone;
28import com.android.internal.telephony.sip.SipPhoneFactory;
29
30/**
31 * {@hide}
32 */
33public class PhoneFactory {
34    static final String LOG_TAG = "PHONE";
35    static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000;
36    static final int SOCKET_OPEN_MAX_RETRY = 3;
37    //***** Class Variables
38
39    static private Phone sProxyPhone = null;
40    static private CommandsInterface sCommandsInterface = null;
41
42    static private boolean sMadeDefaults = false;
43    static private PhoneNotifier sPhoneNotifier;
44    static private Looper sLooper;
45    static private Context sContext;
46
47    static final int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
48
49    static final int preferredCdmaSubscription = RILConstants.PREFERRED_CDMA_SUBSCRIPTION;
50
51    //***** Class Methods
52
53    public static void makeDefaultPhones(Context context) {
54        makeDefaultPhone(context);
55    }
56
57    /**
58     * FIXME replace this with some other way of making these
59     * instances
60     */
61    public static void makeDefaultPhone(Context context) {
62        synchronized(Phone.class) {
63            if (!sMadeDefaults) {
64                sLooper = Looper.myLooper();
65                sContext = context;
66
67                if (sLooper == null) {
68                    throw new RuntimeException(
69                        "PhoneFactory.makeDefaultPhone must be called from Looper thread");
70                }
71
72                int retryCount = 0;
73                for(;;) {
74                    boolean hasException = false;
75                    retryCount ++;
76
77                    try {
78                        // use UNIX domain socket to
79                        // prevent subsequent initialization
80                        new LocalServerSocket("com.android.internal.telephony");
81                    } catch (java.io.IOException ex) {
82                        hasException = true;
83                    }
84
85                    if ( !hasException ) {
86                        break;
87                    } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
88                        throw new RuntimeException("PhoneFactory probably already running");
89                    } else {
90                        try {
91                            Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
92                        } catch (InterruptedException er) {
93                        }
94                    }
95                }
96
97                sPhoneNotifier = new DefaultPhoneNotifier();
98
99                //Get preferredNetworkMode from Settings.System
100                int networkMode = Settings.Secure.getInt(context.getContentResolver(),
101                        Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode);
102                Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));
103
104                //Get preferredNetworkMode from Settings.System
105                int cdmaSubscription = Settings.Secure.getInt(context.getContentResolver(),
106                        Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION, preferredCdmaSubscription);
107                Log.i(LOG_TAG, "Cdma Subscription set to " + Integer.toString(cdmaSubscription));
108
109                //reads the system properties and makes commandsinterface
110                sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
111
112                int phoneType = getPhoneType(networkMode);
113                if (phoneType == Phone.PHONE_TYPE_GSM) {
114                    Log.i(LOG_TAG, "Creating GSMPhone");
115                    sProxyPhone = new PhoneProxy(new GSMPhone(context,
116                            sCommandsInterface, sPhoneNotifier));
117                } else if (phoneType == Phone.PHONE_TYPE_CDMA) {
118                    Log.i(LOG_TAG, "Creating CDMAPhone");
119                    sProxyPhone = new PhoneProxy(new CDMAPhone(context,
120                            sCommandsInterface, sPhoneNotifier));
121                }
122
123                sMadeDefaults = true;
124            }
125        }
126    }
127
128    /*
129     * This function returns the type of the phone, depending
130     * on the network mode.
131     *
132     * @param network mode
133     * @return Phone Type
134     */
135    public static int getPhoneType(int networkMode) {
136        switch(networkMode) {
137        case RILConstants.NETWORK_MODE_CDMA:
138        case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
139        case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
140            return Phone.PHONE_TYPE_CDMA;
141
142        case RILConstants.NETWORK_MODE_WCDMA_PREF:
143        case RILConstants.NETWORK_MODE_GSM_ONLY:
144        case RILConstants.NETWORK_MODE_WCDMA_ONLY:
145        case RILConstants.NETWORK_MODE_GSM_UMTS:
146            return Phone.PHONE_TYPE_GSM;
147
148        case RILConstants.NETWORK_MODE_GLOBAL:
149            return Phone.PHONE_TYPE_CDMA;
150        default:
151            return Phone.PHONE_TYPE_GSM;
152        }
153    }
154
155    public static Phone getDefaultPhone() {
156        if (sLooper != Looper.myLooper()) {
157            throw new RuntimeException(
158                "PhoneFactory.getDefaultPhone must be called from Looper thread");
159        }
160
161        if (!sMadeDefaults) {
162            throw new IllegalStateException("Default phones haven't been made yet!");
163        }
164       return sProxyPhone;
165    }
166
167    public static Phone getCdmaPhone() {
168        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
169            Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier);
170            return phone;
171        }
172    }
173
174    public static Phone getGsmPhone() {
175        synchronized(PhoneProxy.lockForRadioTechnologyChange) {
176            Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier);
177            return phone;
178        }
179    }
180
181    /**
182     * Makes a {@link SipPhone} object.
183     * @param sipUri the local SIP URI the phone runs on
184     * @return the {@code SipPhone} object or null if the SIP URI is not valid
185     */
186    public static SipPhone makeSipPhone(String sipUri) {
187        return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier);
188    }
189}
190