blob: 7286c76a3785ae3b9f9444734342e11b5f4c1e3b [file] [log] [blame]
Jonathan Basseri6465afd2015-02-25 13:05:57 -08001/**
2 * Copyright (c) 2015, 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
Jonathan Basseri6465afd2015-02-25 13:05:57 -080017package com.android.phone;
18
19import static android.Manifest.permission.READ_PHONE_STATE;
20import static com.android.internal.telephony.uicc.IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED;
21
22import android.app.ActivityManagerNative;
23import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.ServiceConnection;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070029import android.content.pm.PackageInfo;
Jonathan Basseric31f1f32015-05-12 10:13:03 -070030import android.content.pm.PackageManager;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080031import android.database.sqlite.SQLiteDatabase;
32import android.database.sqlite.SQLiteOpenHelper;
33import android.os.AsyncResult;
Junda Liu43d723a2015-05-12 17:23:45 -070034import android.os.Binder;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080035import android.os.Handler;
36import android.os.IBinder;
37import android.os.Message;
Jonathan Basseric31f1f32015-05-12 10:13:03 -070038import android.os.PersistableBundle;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080039import android.os.RemoteException;
40import android.os.ServiceManager;
41import android.os.UserHandle;
42import android.service.carrier.CarrierConfigService;
43import android.service.carrier.CarrierIdentifier;
44import android.service.carrier.ICarrierConfigService;
45import android.telephony.CarrierConfigManager;
46import android.telephony.SubscriptionManager;
47import android.telephony.TelephonyManager;
48import android.util.Log;
49
50import com.android.internal.telephony.ICarrierConfigLoader;
51import com.android.internal.telephony.IccCardConstants;
52import com.android.internal.telephony.Phone;
53import com.android.internal.telephony.PhoneConstants;
54import com.android.internal.telephony.PhoneFactory;
55import com.android.internal.telephony.TelephonyIntents;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070056import com.android.internal.util.FastXmlSerializer;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080057
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070058import org.xmlpull.v1.XmlPullParser;
59import org.xmlpull.v1.XmlPullParserException;
60import org.xmlpull.v1.XmlPullParserFactory;
61
62import java.io.File;
Junda Liu43d723a2015-05-12 17:23:45 -070063import java.io.FileDescriptor;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070064import java.io.FileInputStream;
65import java.io.FileNotFoundException;
66import java.io.FileOutputStream;
67import java.io.IOException;
Junda Liu43d723a2015-05-12 17:23:45 -070068import java.io.PrintWriter;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080069import java.util.List;
70
71/**
72 * CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
73 * TODO: implement persist cache
74 * TODO: add gid2 to phone
75 * TODO: handle package install/uninstall events
76 */
77
78public class CarrierConfigLoader extends ICarrierConfigLoader.Stub {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -070079 private static final String LOG_TAG = "CarrierConfigLoader";
Jonathan Basseri6465afd2015-02-25 13:05:57 -080080 // Package name for default carrier config app, bundled with system image.
81 private static final String DEFAULT_CARRIER_CONFIG_PACKAGE = "com.android.carrierconfig";
82
83 /** The singleton instance. */
84 private static CarrierConfigLoader sInstance;
85 // The context for phone app, passed from PhoneGlobals.
86 private Context mContext;
87 // Carrier configs from default app, indexed by phoneID.
Jonathan Basseric31f1f32015-05-12 10:13:03 -070088 private PersistableBundle[] mConfigFromDefaultApp;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080089 // Carrier configs from privileged carrier config app, indexed by phoneID.
Jonathan Basseric31f1f32015-05-12 10:13:03 -070090 private PersistableBundle[] mConfigFromCarrierApp;
Jonathan Basseri6465afd2015-02-25 13:05:57 -080091 // Service connection for binding to config app.
92 private ConfigServiceConnection[] mServiceConnection;
93
94 // Broadcast receiver for SIM and pkg intents, register intent filter in constructor.
95 private final BroadcastReceiver mReceiver = new ConfigLoaderBroadcastReceiver();
96
97 // Message codes; see mHandler below.
98 // Request from SubscriptionInfoUpdater when SIM becomes absent or error.
99 private static final int EVENT_CLEAR_CONFIG = 0;
100 // Request from SubscriptionInfoUpdater to update config.
101 private static final int EVENT_UPDATE_CONFIG = 1;
102 // Request from carrier app to reload config.
103 private static final int EVENT_RELOAD_CONFIG = 2;
104 // Has connected to default app.
105 private static final int EVENT_CONNECTED_TO_DEFAULT = 3;
106 // Has connected to carrier app.
107 private static final int EVENT_CONNECTED_TO_CARRIER = 4;
108 // Config has been loaded from default app.
109 private static final int EVENT_LOADED_FROM_DEFAULT = 5;
110 // Config has been loaded from carrier app.
111 private static final int EVENT_LOADED_FROM_CARRIER = 6;
112
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700113 // Tags used for saving and restoring XML documents.
114 private static final String TAG_DOCUMENT = "carrier_config";
115 private static final String TAG_VERSION = "package_version";
116 private static final String TAG_BUNDLE = "bundle_data";
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800117
118 // Handler to process various events.
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700119 //
120 // For each phoneId, state transition should be: default app bind->connected->loaded, carrier
121 // app (if exists) bind-> connected->loaded. At any time, at most one connection is active. If
122 // events are not in this order, previous connection will be unbind, so only latest event takes
123 // effect.
124 //
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800125 // We broadcast config change when:
126 // 1. loaded from carrier app
127 // 2. loaded from default app if no carrier app
128 // 3. config cleared, possibly due to sim removed
129 // 4. bind or IPC error
130 private Handler mHandler = new Handler() {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700131 @Override
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800132 public void handleMessage(Message msg) {
133 int phoneId = msg.arg1;
134 log("mHandler: " + msg.what + " phoneId: " + phoneId);
135 CarrierIdentifier carrierId;
136 ConfigServiceConnection conn;
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700137 PersistableBundle config;
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800138 switch (msg.what) {
139 case EVENT_CLEAR_CONFIG:
140 mConfigFromDefaultApp[phoneId] = null;
141 mConfigFromCarrierApp[phoneId] = null;
142 mServiceConnection[phoneId] = null;
143 broadcastConfigChangedIntent(phoneId);
144 break;
145 case EVENT_UPDATE_CONFIG:
146 // Use persist cache to avoid loading from app.
147 // Fall through to next event if cache not hit.
148 case EVENT_RELOAD_CONFIG:
149 if (!bindToConfigPackage(DEFAULT_CARRIER_CONFIG_PACKAGE,
150 phoneId, EVENT_CONNECTED_TO_DEFAULT)) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700151 // Send bcast if bind fails
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800152 broadcastConfigChangedIntent(phoneId);
153 }
154 break;
155
156 case EVENT_CONNECTED_TO_DEFAULT:
157 carrierId = getCarrierIdForPhoneId(phoneId);
158 conn = (ConfigServiceConnection) msg.obj;
159 // If new service connection has been created, unbind.
160 if (mServiceConnection[phoneId] != conn || conn.service == null) {
161 mContext.unbindService(conn);
162 break;
163 }
164 try {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700165 ICarrierConfigService configService = ICarrierConfigService.Stub
166 .asInterface(conn.service);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800167 config = configService.getCarrierConfig(carrierId);
168 mConfigFromDefaultApp[phoneId] = config;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700169 mHandler.sendMessage(
170 mHandler.obtainMessage(EVENT_LOADED_FROM_DEFAULT, phoneId));
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800171 } catch (RemoteException ex) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700172 loge("Failed to get carrier config: " + ex.toString());
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800173 } finally {
174 mContext.unbindService(mServiceConnection[phoneId]);
175 }
176 break;
177
178 case EVENT_LOADED_FROM_DEFAULT:
179 if (mServiceConnection[phoneId] == null) {
180 break;
181 }
182 List<String> carrierPackageNames = TelephonyManager.from(mContext)
Junda Liu0bdd55b2015-05-04 14:32:58 -0700183 .getCarrierPackageNamesForIntentAndPhone(
184 new Intent(CarrierConfigService.SERVICE_INTERFACE), phoneId);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800185 log("Found carrier config app: " + carrierPackageNames);
186 if (carrierPackageNames != null && carrierPackageNames.size() > 0) {
187 if (!bindToConfigPackage(carrierPackageNames.get(0),
188 phoneId, EVENT_CONNECTED_TO_CARRIER)) {
189 broadcastConfigChangedIntent(phoneId);
190 }
191 } else {
192 broadcastConfigChangedIntent(phoneId);
193 }
194 break;
195
196 case EVENT_CONNECTED_TO_CARRIER:
197 carrierId = getCarrierIdForPhoneId(phoneId);
198 conn = (ConfigServiceConnection) msg.obj;
199 // If new service connection has been created, unbind.
200 if (mServiceConnection[phoneId] != conn ||
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700201 conn.service == null) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800202 mContext.unbindService(conn);
203 break;
204 }
205 try {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700206 ICarrierConfigService configService = ICarrierConfigService.Stub
207 .asInterface(conn.service);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800208 config = configService.getCarrierConfig(carrierId);
209 mConfigFromCarrierApp[phoneId] = config;
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700210 mHandler.sendMessage(
211 mHandler.obtainMessage(EVENT_LOADED_FROM_CARRIER, phoneId));
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800212 } catch (RemoteException ex) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700213 loge("Failed to get carrier config: " + ex.toString());
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800214 } finally {
215 mContext.unbindService(mServiceConnection[phoneId]);
216 }
217 break;
218
219 case EVENT_LOADED_FROM_CARRIER:
220 if (mServiceConnection[phoneId] == null) {
221 break;
222 }
223 broadcastConfigChangedIntent(phoneId);
224 break;
225 }
226 }
227 };
228
229 /**
230 * Constructs a CarrierConfigLoader, registers it as a service, and registers a broadcast
231 * receiver for relevant events.
232 */
233 private CarrierConfigLoader(Context context) {
234 mContext = context;
235
236 // Register for package updates.
237 IntentFilter triggers = new IntentFilter();
238 triggers.addAction(Intent.ACTION_PACKAGE_ADDED);
239 triggers.addAction(Intent.ACTION_PACKAGE_CHANGED);
240 triggers.addAction(Intent.ACTION_PACKAGE_REMOVED);
241 mContext.registerReceiver(mReceiver, triggers);
242
243 int numPhones = TelephonyManager.from(context).getPhoneCount();
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700244 mConfigFromDefaultApp = new PersistableBundle[numPhones];
245 mConfigFromCarrierApp = new PersistableBundle[numPhones];
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800246 mServiceConnection = new ConfigServiceConnection[numPhones];
247 // Make this service available through ServiceManager.
248 ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
249 log("CarrierConfigLoader has started");
250 }
251
252 /**
253 * Initialize the singleton CarrierConfigLoader instance.
254 *
255 * This is only done once, at startup, from {@link com.android.phone.PhoneApp#onCreate}.
256 */
257 /* package */
258 static CarrierConfigLoader init(Context context) {
259 synchronized (CarrierConfigLoader.class) {
260 if (sInstance == null) {
261 sInstance = new CarrierConfigLoader(context);
262 } else {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700263 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800264 }
265 return sInstance;
266 }
267 }
268
269 private void broadcastConfigChangedIntent(int phoneId) {
270 Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
271 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
272 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
273 ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700274 UserHandle.USER_ALL);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800275 }
276
277 /** Binds to the default or carrier config app. */
278 private boolean bindToConfigPackage(String pkgName, int phoneId, int eventId) {
279 log("Binding to " + pkgName + " for phone " + phoneId);
280 Intent carrierConfigService = new Intent(CarrierConfigService.SERVICE_INTERFACE);
281 carrierConfigService.setPackage(pkgName);
282 mServiceConnection[phoneId] = new ConfigServiceConnection(phoneId, eventId);
283 try {
284 return mContext.bindService(carrierConfigService, mServiceConnection[phoneId],
285 Context.BIND_AUTO_CREATE);
286 } catch (SecurityException ex) {
287 return false;
288 }
289 }
290
291 private CarrierIdentifier getCarrierIdForPhoneId(int phoneId) {
292 String mcc = "";
293 String mnc = "";
294 String imsi = "";
295 String gid1 = "";
296 String gid2 = "";
297 String spn = TelephonyManager.from(mContext).getSimOperatorNameForPhone(phoneId);
298 String simOperator = TelephonyManager.from(mContext).getSimOperatorNumericForPhone(phoneId);
Jonathan Basseri1fa437c2015-04-20 11:08:18 -0700299 // A valid simOperator should be 5 or 6 digits, depending on the length of the MNC.
300 if (simOperator != null && simOperator.length() >= 3) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800301 mcc = simOperator.substring(0, 3);
302 mnc = simOperator.substring(3);
303 }
304 Phone phone = PhoneFactory.getPhone(phoneId);
305 if (phone != null) {
306 imsi = phone.getSubscriberId();
307 gid1 = phone.getGroupIdLevel1();
308 // add gid2 after phone supports it.
309 }
310
311 return new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2);
312 }
313
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700314 /**
315 * Writes a bundle to an XML file.
316 *
317 * The bundle will be written to a file named after the package name and ICCID, so that it can
318 * be restored later with {@link @restoreConfigFromXml}. The XML output will include the bundle
319 * and the current version of the specified package. In case of errors, no file will be written.
320 *
321 * @param packageName the name of the package from which we fetched this bundle.
322 * @param iccid the ICCID of the subscription for which this bundle was fetched.
323 * @param config the bundle to be written.
324 */
325 private void saveConfigToXml(String packageName, String iccid, PersistableBundle config) {
326 final String version = getPackageVersion(packageName);
327 if (version == null) {
328 loge("Failed to get package version for: " + packageName);
329 return;
330 }
331
332 FileOutputStream outFile = null;
333 try {
334 outFile = new FileOutputStream(
335 new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
336 FastXmlSerializer out = new FastXmlSerializer();
337 out.setOutput(outFile, "utf-8");
338 out.startDocument("utf-8", true);
339 out.startTag(null, TAG_DOCUMENT);
340 out.startTag(null, TAG_VERSION);
341 out.text(version);
342 out.endTag(null, TAG_VERSION);
343 out.startTag(null, TAG_BUNDLE);
344 config.saveToXml(out);
345 out.endTag(null, TAG_BUNDLE);
346 out.endTag(null, TAG_DOCUMENT);
347 out.endDocument();
348 out.flush();
349 outFile.close();
350 }
351 catch (IOException e) {
352 loge(e.toString());
353 }
354 catch (XmlPullParserException e) {
355 loge(e.toString());
356 }
357 }
358
359 /**
360 * Reads a bundle from an XML file.
361 *
362 * This restores a bundle that was written with {@link #saveConfigToXml}. This returns the saved
363 * config bundle for the given package and ICCID. If the saved config is for a different package
364 * version than the current version, then null will be returned.
365 *
366 * @param packageName the name of the package from which we fetched this bundle.
367 * @param iccid the ICCID of the subscription for which this bundle was fetched.
368 * @return the bundle from the XML file. Returns null if there is no saved config, the saved
369 * version does not match, or reading config fails.
370 */
371 private PersistableBundle restoreConfigFromXml(String packageName, String iccid) {
372 final String version = getPackageVersion(packageName);
373 if (version == null) {
374 loge("Failed to get package version for: " + packageName);
375 return null;
376 }
377
378 PersistableBundle restoredBundle = null;
379 FileInputStream inFile = null;
380 try {
381 inFile = new FileInputStream(
382 new File(mContext.getFilesDir(), getFilenameForConfig(packageName, iccid)));
383 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
384 parser.setInput(inFile, "utf-8");
385
386 int event;
387 while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) {
388
389 if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) {
390 String savedVersion = parser.nextText();
391 if (!version.equals(savedVersion)) {
392 log("Saved version mismatch: " + version + " vs " + savedVersion);
393 break;
394 }
395 }
396
397 if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) {
398 restoredBundle = PersistableBundle.restoreFromXml(parser);
399 }
400 }
401 inFile.close();
402 }
403 catch (FileNotFoundException e) {
404 loge(e.toString());
405 }
406 catch (XmlPullParserException e) {
407 loge(e.toString());
408 }
409 catch (IOException e) {
410 loge(e.toString());
411 }
412
413 return restoredBundle;
414 }
415
416 /** Builds a canonical file name for a config file. */
417 private String getFilenameForConfig(String packageName, String iccid) {
418 return "carrierconfig-" + packageName + "-" + iccid + ".xml";
419 }
420
421 /** Return the current version of a package, or null if the name is not found. */
422 private String getPackageVersion(String packageName) {
423 try {
424 PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
425 return info.versionName;
426 } catch (PackageManager.NameNotFoundException e) {
427 return null;
428 }
429 }
430
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800431 @Override
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700432 public PersistableBundle getConfigForSubId(int subId) {
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800433 int phoneId = SubscriptionManager.getPhoneId(subId);
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700434 PersistableBundle retConfig = CarrierConfigManager.getDefaultConfig();
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800435 if (SubscriptionManager.isValidPhoneId(phoneId)) {
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700436 PersistableBundle config = mConfigFromDefaultApp[phoneId];
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700437 if (config != null)
438 retConfig.putAll(config);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800439 config = mConfigFromCarrierApp[phoneId];
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700440 if (config != null)
441 retConfig.putAll(config);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800442 }
443 return retConfig;
444 }
445
446 @Override
447 public void reloadCarrierConfigForSubId(int subId) {
448 int phoneId = SubscriptionManager.getPhoneId(subId);
449 if (SubscriptionManager.isValidPhoneId(phoneId)) {
450 mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELOAD_CONFIG, phoneId));
451 } else {
452 log("Ignore invalid phoneId: " + phoneId + " for subId: " + subId);
453 }
454 }
455
456 @Override
457 public void updateConfigForPhoneId(int phoneId, String simState) {
458 log("update config for phoneId: " + phoneId + " simState: " + simState);
459 if (!SubscriptionManager.isValidPhoneId(phoneId)) {
460 return;
461 }
462 // requires Java 7 for switch on string.
463 switch (simState) {
464 case IccCardConstants.INTENT_VALUE_ICC_ABSENT:
465 case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR:
466 case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN:
467 mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId));
468 break;
469 case IccCardConstants.INTENT_VALUE_ICC_LOADED:
470 case IccCardConstants.INTENT_VALUE_ICC_LOCKED:
471 mHandler.sendMessage(mHandler.obtainMessage(EVENT_UPDATE_CONFIG, phoneId));
472 break;
473 }
474 }
475
Junda Liu43d723a2015-05-12 17:23:45 -0700476 @Override
477 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
478 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
479 != PackageManager.PERMISSION_GRANTED) {
480 pw.println("Permission Denial: can't dump carrierconfig from from pid="
481 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
482 return;
483 }
484 pw.println("CarrierConfigLoader: " + this);
485 for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
486 pw.println(" Phone Id=" + i);
487 pw.println(" mConfigFromDefaultApp=" + mConfigFromDefaultApp[i]);
488 pw.println(" mConfigFromCarrierApp=" + mConfigFromCarrierApp[i]);
489 }
490 }
491
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800492 private class ConfigServiceConnection implements ServiceConnection {
493 int phoneId;
494 int eventId;
495 IBinder service;
496
497 public ConfigServiceConnection(int phoneId, int eventId) {
498 this.phoneId = phoneId;
499 this.eventId = eventId;
500 }
501
502 @Override
503 public void onServiceConnected(ComponentName name, IBinder service) {
504 log("Connected to config app: " + name.flattenToString());
505 this.service = service;
506 mHandler.sendMessage(mHandler.obtainMessage(eventId, phoneId, -1, this));
507 }
508
509 @Override
510 public void onServiceDisconnected(ComponentName name) {
511 this.service = null;
512 }
513 }
514
515 private class ConfigLoaderBroadcastReceiver extends BroadcastReceiver {
516 @Override
517 public void onReceive(Context context, Intent intent) {
518 String action = intent.getAction();
519 log("Receive action: " + action);
520 }
521 }
522
523 private static void log(String msg) {
Jonathan Basseri6b50e9f2015-05-12 20:18:31 -0700524 Log.d(LOG_TAG, msg);
525 }
526
527 private static void loge(String msg) {
528 Log.e(LOG_TAG, msg);
Jonathan Basseri6465afd2015-02-25 13:05:57 -0800529 }
530}