110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian/*
210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * Copyright (C) 2016 The Android Open Source Project
310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *
410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * Licensed under the Apache License, Version 2.0 (the "License");
510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * you may not use this file except in compliance with the License.
610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * You may obtain a copy of the License at
710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *
810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *      http://www.apache.org/licenses/LICENSE-2.0
910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *
1010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * Unless required by applicable law or agreed to in writing, software
1110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * distributed under the License is distributed on an "AS IS" BASIS,
1210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * See the License for the specific language governing permissions and
1410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * limitations under the License.
1510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian */
1610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
1710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianpackage com.android.dialer.location;
1810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
1910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.app.PendingIntent;
2010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.content.BroadcastReceiver;
2110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.content.Context;
2210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.content.Intent;
2310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.location.Address;
2410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.location.Geocoder;
2510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.location.Location;
2610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.location.LocationManager;
2710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.preference.PreferenceManager;
2810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.support.annotation.NonNull;
2910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.support.annotation.Nullable;
3010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.support.annotation.VisibleForTesting;
313ed0c281a143789ea8187dba60dba6c6b5db9009Eric Erfanianimport android.support.v4.os.UserManagerCompat;
3210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.telephony.TelephonyManager;
3310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport android.text.TextUtils;
3410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.common.Assert;
3510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.common.LogUtil;
3610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.common.concurrent.DialerExecutor.Worker;
372f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanianimport com.android.dialer.common.concurrent.DialerExecutorComponent;
3810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport com.android.dialer.util.PermissionsUtil;
3910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport java.util.List;
4010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianimport java.util.Locale;
4110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
4210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian/**
4310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * This class is used to detect the country where the user is. It is a simplified version of the
4410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * country detector service in the framework. The sources of country location are queried in the
4510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * following order of reliability:
4610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *
4710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * <ul>
4810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *   <li>Mobile network
4910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *   <li>Location manager
5010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *   <li>SIM's country
5110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *   <li>User's default locale
5210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * </ul>
5310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian *
5410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * As far as possible this class tries to replicate the behavior of the system's country detector
5510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * service: 1) Order in priority of sources of country location 2) Mobile network information
5610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * provided by CDMA phones is ignored 3) Location information is updated every 12 hours (instead of
5710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * 24 hours in the system) 4) Location updates only uses the {@link
5810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * LocationManager#PASSIVE_PROVIDER} to avoid active use of the GPS 5) If a location is successfully
5910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * obtained and geocoded, we never fall back to use of the SIM's country (for the system, the
6010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * fallback never happens without a reboot) 6) Location is not used if the device does not implement
6110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian * a {@link android.location.Geocoder}
6210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian */
6310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanianpublic class CountryDetector {
6410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private static final String KEY_PREFERENCE_TIME_UPDATED = "preference_time_updated";
6510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  static final String KEY_PREFERENCE_CURRENT_COUNTRY = "preference_current_country";
6610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  // Wait 12 hours between updates
6710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private static final long TIME_BETWEEN_UPDATES_MS = 1000L * 60 * 60 * 12;
6810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  // Minimum distance before an update is triggered, in meters. We don't need this to be too
6910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  // exact because all we care about is what country the user is in.
7010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private static final long DISTANCE_BETWEEN_UPDATES_METERS = 5000;
7110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  // Used as a default country code when all the sources of country data have failed in the
7210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  // exceedingly rare event that the device does not have a default locale set for some reason.
7310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private static final String DEFAULT_COUNTRY_ISO = "US";
7410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
7510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  @VisibleForTesting static CountryDetector sInstance;
7610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
7710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private final TelephonyManager telephonyManager;
7810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private final LocaleProvider localeProvider;
7910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private final Geocoder geocoder;
8010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private final Context appContext;
8110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
8210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  @VisibleForTesting
8310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  CountryDetector(
8410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      Context appContext,
8510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      TelephonyManager telephonyManager,
8610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      LocationManager locationManager,
8710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      LocaleProvider localeProvider,
8810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      Geocoder geocoder) {
8910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    this.telephonyManager = telephonyManager;
9010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    this.localeProvider = localeProvider;
9110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    this.appContext = appContext;
9210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    this.geocoder = geocoder;
9310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
9410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    // If the device does not implement Geocoder there is no point trying to get location updates
9510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    // because we cannot retrieve the country based on the location anyway.
9610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (Geocoder.isPresent()) {
9710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      registerForLocationUpdates(appContext, locationManager);
9810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
9910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
10010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
10110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private static void registerForLocationUpdates(Context context, LocationManager locationManager) {
10210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (!PermissionsUtil.hasLocationPermissions(context)) {
10310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      LogUtil.w(
10410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian          "CountryDetector.registerForLocationUpdates",
10510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian          "no location permissions, not registering for location updates");
10610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      return;
10710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
10810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
10910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    LogUtil.i("CountryDetector.registerForLocationUpdates", "registering for location updates");
11010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
11110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    final Intent activeIntent = new Intent(context, LocationChangedReceiver.class);
11210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    final PendingIntent pendingIntent =
11310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        PendingIntent.getBroadcast(context, 0, activeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
11410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
11510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    locationManager.requestLocationUpdates(
11610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        LocationManager.PASSIVE_PROVIDER,
11710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        TIME_BETWEEN_UPDATES_MS,
11810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        DISTANCE_BETWEEN_UPDATES_METERS,
11910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        pendingIntent);
12010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
12110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
12210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  /** @return the single instance of the {@link CountryDetector} */
12310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  public static synchronized CountryDetector getInstance(Context context) {
12410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (sInstance == null) {
12510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      Context appContext = context.getApplicationContext();
12610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      sInstance =
12710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian          new CountryDetector(
12810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              appContext,
12910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
13010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              (LocationManager) context.getSystemService(Context.LOCATION_SERVICE),
13110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              Locale::getDefault,
13210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              new Geocoder(appContext));
13310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
13410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return sInstance;
13510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
13610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
13710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  public String getCurrentCountryIso() {
13810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    String result = null;
13910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (isNetworkCountryCodeAvailable()) {
14010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      result = getNetworkBasedCountryIso();
14110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
14210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (TextUtils.isEmpty(result)) {
14310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      result = getLocationBasedCountryIso();
14410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
14510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (TextUtils.isEmpty(result)) {
14610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      result = getSimBasedCountryIso();
14710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
14810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (TextUtils.isEmpty(result)) {
14910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      result = getLocaleBasedCountryIso();
15010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
15110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (TextUtils.isEmpty(result)) {
15210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      result = DEFAULT_COUNTRY_ISO;
15310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
15410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return result.toUpperCase(Locale.US);
15510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
15610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
15710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  /** @return the country code of the current telephony network the user is connected to. */
15810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private String getNetworkBasedCountryIso() {
15910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return telephonyManager.getNetworkCountryIso();
16010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
16110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
16210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  /** @return the geocoded country code detected by the {@link LocationManager}. */
1633ed0c281a143789ea8187dba60dba6c6b5db9009Eric Erfanian  @Nullable
16410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private String getLocationBasedCountryIso() {
1653ed0c281a143789ea8187dba60dba6c6b5db9009Eric Erfanian    if (!Geocoder.isPresent()
1663ed0c281a143789ea8187dba60dba6c6b5db9009Eric Erfanian        || !PermissionsUtil.hasLocationPermissions(appContext)
1673ed0c281a143789ea8187dba60dba6c6b5db9009Eric Erfanian        || !UserManagerCompat.isUserUnlocked(appContext)) {
16810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      return null;
16910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
17010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return PreferenceManager.getDefaultSharedPreferences(appContext)
17110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .getString(KEY_PREFERENCE_CURRENT_COUNTRY, null);
17210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
17310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
17410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  /** @return the country code of the SIM card currently inserted in the device. */
17510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private String getSimBasedCountryIso() {
17610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return telephonyManager.getSimCountryIso();
17710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
17810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
17910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  /** @return the country code of the user's currently selected locale. */
18010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private String getLocaleBasedCountryIso() {
18110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    Locale defaultLocale = localeProvider.getLocale();
18210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    if (defaultLocale != null) {
18310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      return defaultLocale.getCountry();
18410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
18510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return null;
18610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
18710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
18810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private boolean isNetworkCountryCodeAvailable() {
18910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    // On CDMA TelephonyManager.getNetworkCountryIso() just returns the SIM's country code.
19010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    // In this case, we want to ignore the value returned and fallback to location instead.
19110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    return telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM;
19210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
19310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
19410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  /** Interface for accessing the current locale. */
19510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  interface LocaleProvider {
19610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    Locale getLocale();
19710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
19810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
19910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  public static class LocationChangedReceiver extends BroadcastReceiver {
20010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
20110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    @Override
20210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    public void onReceive(final Context context, Intent intent) {
20310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      if (!intent.hasExtra(LocationManager.KEY_LOCATION_CHANGED)) {
20410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        return;
20510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      }
20610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
20710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      final Location location =
20810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian          (Location) intent.getExtras().get(LocationManager.KEY_LOCATION_CHANGED);
20910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
21010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      // TODO: rething how we access the gecoder here, right now we have to set the static instance
21110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      // of CountryDetector to make this work for tests which is weird
21210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      // (see CountryDetectorTest.locationChangedBroadcast_GeocodesLocation)
21310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      processLocationUpdate(context, CountryDetector.getInstance(context).geocoder, location);
21410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
21510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
21610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
21710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private static void processLocationUpdate(
21810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      Context appContext, Geocoder geocoder, Location location) {
2192f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian    DialerExecutorComponent.get(appContext)
2202f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        .dialerExecutorFactory()
2212f1c7586bcce334ca69022eb8dc6d8965ceb6a05Eric Erfanian        .createNonUiTaskBuilder(new GeocodeCountryWorker(geocoder))
22210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .onSuccess(
22310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian            country -> {
22410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              if (country == null) {
22510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                return;
22610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              }
22710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
22810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian              PreferenceManager.getDefaultSharedPreferences(appContext)
22910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                  .edit()
23010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                  .putLong(CountryDetector.KEY_PREFERENCE_TIME_UPDATED, System.currentTimeMillis())
23110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                  .putString(CountryDetector.KEY_PREFERENCE_CURRENT_COUNTRY, country)
23210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                  .apply();
23310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian            })
23410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .onFailure(
23510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian            throwable ->
23610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                LogUtil.w(
23710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                    "CountryDetector.processLocationUpdate",
23810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                    "exception occurred when getting geocoded country from location",
23910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian                    throwable))
24010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .build()
24110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        .executeParallel(location);
24210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
24310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
24410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  /** Worker that given a {@link Location} returns an ISO 3166-1 two letter country code. */
24510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  private static class GeocodeCountryWorker implements Worker<Location, String> {
24610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    @NonNull private final Geocoder geocoder;
24710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
24810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    GeocodeCountryWorker(@NonNull Geocoder geocoder) {
24910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      this.geocoder = Assert.isNotNull(geocoder);
25010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
25110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
25210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    /** @return the ISO 3166-1 two letter country code if geocoded, else null */
25310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    @Nullable
25410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    @Override
25510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    public String doInBackground(@Nullable Location location) throws Throwable {
25610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      if (location == null) {
25710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        return null;
25810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      }
25910b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian
26010b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      List<Address> addresses =
26110b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian          geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
26210b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      if (addresses != null && !addresses.isEmpty()) {
26310b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian        return addresses.get(0).getCountryCode();
26410b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      }
26510b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian      return null;
26610b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian    }
26710b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian  }
26810b34a5ebf12e97ecba0caf3c8e30b476b038a96Eric Erfanian}
269