blob: bceadc4222c9d32849d679eefe78cd21d53bd352 [file] [log] [blame]
Yorke Lee6a29fcb2014-06-13 16:54:50 -07001package com.android.contacts.common.location;
2
Yorke Lee6a29fcb2014-06-13 16:54:50 -07003import android.content.Context;
Yorke Lee6a29fcb2014-06-13 16:54:50 -07004import android.telephony.TelephonyManager;
5import android.text.TextUtils;
Yorke Lee3a52e632015-05-21 11:04:14 -07006import android.util.Log;
Yorke Lee6a29fcb2014-06-13 16:54:50 -07007
Yorke Lee6a29fcb2014-06-13 16:54:50 -07008import java.util.Locale;
9
10/**
11 * This class is used to detect the country where the user is. It is a simplified version of the
12 * country detector service in the framework. The sources of country location are queried in the
13 * following order of reliability:
14 * <ul>
15 * <li>Mobile network</li>
Yorke Lee6a29fcb2014-06-13 16:54:50 -070016 * <li>SIM's country</li>
17 * <li>User's default locale</li>
18 * </ul>
19 *
20 * As far as possible this class tries to replicate the behavior of the system's country detector
21 * service:
22 * 1) Order in priority of sources of country location
23 * 2) Mobile network information provided by CDMA phones is ignored
guanxiongliu4a68a112016-05-09 17:32:00 -070024 */
Yorke Lee6a29fcb2014-06-13 16:54:50 -070025public class CountryDetector {
26 private static final String TAG = "CountryDetector";
27
Yorke Lee6a29fcb2014-06-13 16:54:50 -070028 private static CountryDetector sInstance;
29
guanxiongliu4a68a112016-05-09 17:32:00 -070030 private final Context mContext;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070031 private final LocaleProvider mLocaleProvider;
guanxiongliu4a68a112016-05-09 17:32:00 -070032 private final TelephonyManager mTelephonyManager;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070033
34 // Used as a default country code when all the sources of country data have failed in the
35 // exceedingly rare event that the device does not have a default locale set for some reason.
36 private final String DEFAULT_COUNTRY_ISO = "US";
37
Yorke Lee6a29fcb2014-06-13 16:54:50 -070038 /**
39 * Class that can be used to return the user's default locale. This is in its own class so that
40 * it can be mocked out.
41 */
42 public static class LocaleProvider {
43 public Locale getDefaultLocale() {
44 return Locale.getDefault();
45 }
46 }
47
48 private CountryDetector(Context context) {
49 this (context, (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
Yorke Lee6a29fcb2014-06-13 16:54:50 -070050 new LocaleProvider());
51 }
52
53 private CountryDetector(Context context, TelephonyManager telephonyManager,
guanxiongliu4a68a112016-05-09 17:32:00 -070054 LocaleProvider localeProvider) {
Yorke Lee6a29fcb2014-06-13 16:54:50 -070055 mTelephonyManager = telephonyManager;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070056 mLocaleProvider = localeProvider;
57 mContext = context;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070058 }
59
60 /**
61 * Factory method for {@link CountryDetector} that allows the caller to provide mock objects.
62 */
Yorke Lee6a29fcb2014-06-13 16:54:50 -070063 public CountryDetector getInstanceForTest(Context context, TelephonyManager telephonyManager,
guanxiongliu4a68a112016-05-09 17:32:00 -070064 LocaleProvider localeProvider) {
65 return new CountryDetector(context, telephonyManager, localeProvider);
Yorke Lee6a29fcb2014-06-13 16:54:50 -070066 }
67
68 /**
69 * Returns the instance of the country detector. {@link #initialize(Context)} must have been
70 * called previously.
71 *
72 * @return the initialized country detector.
73 */
74 public synchronized static CountryDetector getInstance(Context context) {
75 if (sInstance == null) {
76 sInstance = new CountryDetector(context.getApplicationContext());
77 }
78 return sInstance;
79 }
80
81 public String getCurrentCountryIso() {
82 String result = null;
83 if (isNetworkCountryCodeAvailable()) {
84 result = getNetworkBasedCountryIso();
85 }
86 if (TextUtils.isEmpty(result)) {
Yorke Lee6a29fcb2014-06-13 16:54:50 -070087 result = getSimBasedCountryIso();
88 }
89 if (TextUtils.isEmpty(result)) {
90 result = getLocaleBasedCountryIso();
91 }
92 if (TextUtils.isEmpty(result)) {
93 result = DEFAULT_COUNTRY_ISO;
94 }
95 return result.toUpperCase(Locale.US);
96 }
97
98 /**
99 * @return the country code of the current telephony network the user is connected to.
100 */
101 private String getNetworkBasedCountryIso() {
102 return mTelephonyManager.getNetworkCountryIso();
103 }
104
105 /**
Yorke Lee6a29fcb2014-06-13 16:54:50 -0700106 * @return the country code of the SIM card currently inserted in the device.
107 */
108 private String getSimBasedCountryIso() {
109 return mTelephonyManager.getSimCountryIso();
110 }
111
112 /**
113 * @return the country code of the user's currently selected locale.
114 */
115 private String getLocaleBasedCountryIso() {
116 Locale defaultLocale = mLocaleProvider.getDefaultLocale();
117 if (defaultLocale != null) {
118 return defaultLocale.getCountry();
119 }
120 return null;
121 }
122
123 private boolean isNetworkCountryCodeAvailable() {
124 // On CDMA TelephonyManager.getNetworkCountryIso() just returns the SIM's country code.
Yorke Lee6a29fcb2014-06-13 16:54:50 -0700125 return mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM;
126 }
Yorke Lee6a29fcb2014-06-13 16:54:50 -0700127}