Ensure that a default SMS app is configured at boot
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / PhoneFactory.java
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
17 package com.android.internal.telephony;
18
19 import android.app.AppOpsManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.pm.PackageInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.PackageManager.NameNotFoundException;
25 import android.net.LocalServerSocket;
26 import android.os.Looper;
27 import android.provider.Settings;
28 import android.telephony.TelephonyManager;
29 import android.telephony.Rlog;
30
31 import com.android.internal.telephony.cdma.CDMAPhone;
32 import com.android.internal.telephony.cdma.CDMALTEPhone;
33 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
34 import com.android.internal.telephony.gsm.GSMPhone;
35 import com.android.internal.telephony.sip.SipPhone;
36 import com.android.internal.telephony.sip.SipPhoneFactory;
37 import com.android.internal.telephony.uicc.UiccController;
38
39 /**
40  * {@hide}
41  */
42 public 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 }