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