blob: 9d08fc0ab522e6794c6ec03d9e96a3349d30902e [file] [log] [blame]
Gary Mai69c182a2016-12-05 13:07:03 -08001package com.android.contacts.location;
Yorke Lee6a29fcb2014-06-13 16:54:50 -07002
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;
6
Yorke Lee6a29fcb2014-06-13 16:54:50 -07007import java.util.Locale;
8
9/**
10 * This class is used to detect the country where the user is. It is a simplified version of the
11 * country detector service in the framework. The sources of country location are queried in the
12 * following order of reliability:
13 * <ul>
14 * <li>Mobile network</li>
Yorke Lee6a29fcb2014-06-13 16:54:50 -070015 * <li>SIM's country</li>
16 * <li>User's default locale</li>
17 * </ul>
18 *
19 * As far as possible this class tries to replicate the behavior of the system's country detector
20 * service:
21 * 1) Order in priority of sources of country location
22 * 2) Mobile network information provided by CDMA phones is ignored
guanxiongliu4a68a112016-05-09 17:32:00 -070023 */
Yorke Lee6a29fcb2014-06-13 16:54:50 -070024public class CountryDetector {
25 private static final String TAG = "CountryDetector";
26
Yorke Lee6a29fcb2014-06-13 16:54:50 -070027 private static CountryDetector sInstance;
28
guanxiongliu4a68a112016-05-09 17:32:00 -070029 private final Context mContext;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070030 private final LocaleProvider mLocaleProvider;
guanxiongliu4a68a112016-05-09 17:32:00 -070031 private final TelephonyManager mTelephonyManager;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070032
33 // Used as a default country code when all the sources of country data have failed in the
34 // exceedingly rare event that the device does not have a default locale set for some reason.
35 private final String DEFAULT_COUNTRY_ISO = "US";
36
Yorke Lee6a29fcb2014-06-13 16:54:50 -070037 /**
38 * Class that can be used to return the user's default locale. This is in its own class so that
39 * it can be mocked out.
40 */
41 public static class LocaleProvider {
42 public Locale getDefaultLocale() {
43 return Locale.getDefault();
44 }
45 }
46
47 private CountryDetector(Context context) {
48 this (context, (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
Yorke Lee6a29fcb2014-06-13 16:54:50 -070049 new LocaleProvider());
50 }
51
52 private CountryDetector(Context context, TelephonyManager telephonyManager,
guanxiongliu4a68a112016-05-09 17:32:00 -070053 LocaleProvider localeProvider) {
Yorke Lee6a29fcb2014-06-13 16:54:50 -070054 mTelephonyManager = telephonyManager;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070055 mLocaleProvider = localeProvider;
56 mContext = context;
Yorke Lee6a29fcb2014-06-13 16:54:50 -070057 }
58
59 /**
60 * Factory method for {@link CountryDetector} that allows the caller to provide mock objects.
61 */
Yorke Lee6a29fcb2014-06-13 16:54:50 -070062 public CountryDetector getInstanceForTest(Context context, TelephonyManager telephonyManager,
guanxiongliu4a68a112016-05-09 17:32:00 -070063 LocaleProvider localeProvider) {
64 return new CountryDetector(context, telephonyManager, localeProvider);
Yorke Lee6a29fcb2014-06-13 16:54:50 -070065 }
66
67 /**
68 * Returns the instance of the country detector. {@link #initialize(Context)} must have been
69 * called previously.
70 *
71 * @return the initialized country detector.
72 */
73 public synchronized static CountryDetector getInstance(Context context) {
74 if (sInstance == null) {
75 sInstance = new CountryDetector(context.getApplicationContext());
76 }
77 return sInstance;
78 }
79
80 public String getCurrentCountryIso() {
81 String result = null;
82 if (isNetworkCountryCodeAvailable()) {
83 result = getNetworkBasedCountryIso();
84 }
85 if (TextUtils.isEmpty(result)) {
Yorke Lee6a29fcb2014-06-13 16:54:50 -070086 result = getSimBasedCountryIso();
87 }
88 if (TextUtils.isEmpty(result)) {
89 result = getLocaleBasedCountryIso();
90 }
91 if (TextUtils.isEmpty(result)) {
92 result = DEFAULT_COUNTRY_ISO;
93 }
94 return result.toUpperCase(Locale.US);
95 }
96
97 /**
98 * @return the country code of the current telephony network the user is connected to.
99 */
100 private String getNetworkBasedCountryIso() {
101 return mTelephonyManager.getNetworkCountryIso();
102 }
103
104 /**
Yorke Lee6a29fcb2014-06-13 16:54:50 -0700105 * @return the country code of the SIM card currently inserted in the device.
106 */
107 private String getSimBasedCountryIso() {
108 return mTelephonyManager.getSimCountryIso();
109 }
110
111 /**
112 * @return the country code of the user's currently selected locale.
113 */
114 private String getLocaleBasedCountryIso() {
115 Locale defaultLocale = mLocaleProvider.getDefaultLocale();
116 if (defaultLocale != null) {
117 return defaultLocale.getCountry();
118 }
119 return null;
120 }
121
122 private boolean isNetworkCountryCodeAvailable() {
123 // On CDMA TelephonyManager.getNetworkCountryIso() just returns the SIM's country code.
Yorke Lee6a29fcb2014-06-13 16:54:50 -0700124 return mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM;
125 }
Yorke Lee6a29fcb2014-06-13 16:54:50 -0700126}