ComprehensiveCountryDetector.java revision a58a8751b4c2ce457f0082a0baaee61312d56195
1a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao/*
2a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Copyright (C) 2010 The Android Open Source Project
3a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
4a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Licensed under the Apache License, Version 2.0 (the "License");
5a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * you may not use this file except in compliance with the License.
6a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * You may obtain a copy of the License at
7a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
8a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *      http://www.apache.org/licenses/LICENSE-2.0
9a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
10a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Unless required by applicable law or agreed to in writing, software
11a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * distributed under the License is distributed on an "AS IS" BASIS,
12a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * See the License for the specific language governing permissions and
14a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * limitations under the License
15a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */
16a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
17a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taopackage com.android.server.location;
18a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
19a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.Locale;
20a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.Timer;
21a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport java.util.TimerTask;
22a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
23a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.content.Context;
24a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Country;
25a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.CountryListener;
26a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Geocoder;
27a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.provider.Settings;
28a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.telephony.PhoneStateListener;
29a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.telephony.ServiceState;
30a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.telephony.TelephonyManager;
31a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.text.TextUtils;
32a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.util.Slog;
33a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
34a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao/**
35a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * This class is used to detect the country where the user is. The sources of
36a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * country are queried in order of reliability, like
37a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <ul>
38a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>Mobile network</li>
39a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>Location</li>
40a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>SIM's country</li>
41a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>Phone's locale</li>
42a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * </ul>
43a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
44a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Call the {@link #detectCountry()} to get the available country immediately.
45a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
46a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * To be notified of the future country change, using the
47a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * {@link #setCountryListener(CountryListener)}
48a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
49a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Using the {@link #stop()} to stop listening to the country change.
50a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
51a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * The country information will be refreshed every
52a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * {@link #LOCATION_REFRESH_INTERVAL} once the location based country is used.
53a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
54a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @hide
55a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */
56a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taopublic class ComprehensiveCountryDetector extends CountryDetectorBase {
57a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
58a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private final static String TAG = "ComprehensiveCountryDetector";
59a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
60a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
61a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * The refresh interval when the location based country was used
62a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
63a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private final static long LOCATION_REFRESH_INTERVAL = 1000 * 60 * 60 * 24; // 1 day
64a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
65a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected CountryDetectorBase mLocationBasedCountryDetector;
66a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Timer mLocationRefreshTimer;
67a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
68a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private final int mPhoneType;
69a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country mCountry;
70a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private TelephonyManager mTelephonyManager;
71a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country mCountryFromLocation;
72a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private boolean mStopped = false;
73a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private ServiceState mLastState;
74a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
75a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
76a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        @Override
77a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public void onServiceStateChanged(ServiceState serviceState) {
78a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // TODO: Find out how often we will be notified, if this method is called too
79a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // many times, let's consider querying the network.
80a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            Slog.d(TAG, "onServiceStateChanged");
81a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // We only care the state change
82a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            if (mLastState == null || mLastState.getState() != serviceState.getState()) {
83a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                detectCountry(true, true);
84a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                mLastState = new ServiceState(serviceState);
85a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
86a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
87a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    };
88a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
89a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
90a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * The listener for receiving the notification from LocationBasedCountryDetector.
91a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
92a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private CountryListener mLocationBasedCountryDetectionListener = new CountryListener() {
93a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public void onCountryDetected(Country country) {
94a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mCountryFromLocation = country;
95a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Don't start the LocationBasedCountryDetector.
96a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            detectCountry(true, false);
97a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            stopLocationBasedDetector();
98a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
99a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    };
100a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
101a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public ComprehensiveCountryDetector(Context context) {
102a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        super(context);
103a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
104a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mPhoneType = mTelephonyManager.getPhoneType();
105a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
106a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
107a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
108a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public Country detectCountry() {
109a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        // Don't start the LocationBasedCountryDetector if we have been stopped.
110a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return detectCountry(false, !mStopped);
111a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
112a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
113a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
114a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public void stop() {
115a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Slog.i(TAG, "Stop the detector.");
116a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        cancelLocationRefresh();
117a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        removePhoneStateListener();
118a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        stopLocationBasedDetector();
119a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mListener = null;
120a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mStopped = true;
121a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
122a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
123a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
124a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Get the country from different sources in order of the reliability.
125a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
126a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country getCountry() {
127a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Country result = null;
128a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        result = getNetworkBasedCountry();
129a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (result == null) {
130a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            result = getLastKnownLocationBasedCountry();
131a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
132a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (result == null) {
133a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            result = getSimBasedCountry();
134a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
135a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (result == null) {
136a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            result = getLocaleCountry();
137a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
138a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return result;
139a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
140a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
141a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
142a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the country from the mobile network.
143a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
144a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getNetworkBasedCountry() {
145a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        String countryIso = null;
146a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        // TODO: The document says the result may be unreliable on CDMA networks. Shall we use
147a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        // it on CDMA phone? We may test the Android primarily used countries.
148a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
149a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            countryIso = mTelephonyManager.getNetworkCountryIso();
150a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            if (!TextUtils.isEmpty(countryIso)) {
151a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                return new Country(countryIso, Country.COUNTRY_SOURCE_NETWORK);
152a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
153a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
154a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return null;
155a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
156a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
157a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
158a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the cached location based country.
159a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
160a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getLastKnownLocationBasedCountry() {
161a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return mCountryFromLocation;
162a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
163a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
164a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
165a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the country from SIM card
166a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
167a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getSimBasedCountry() {
168a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        String countryIso = null;
169a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        countryIso = mTelephonyManager.getSimCountryIso();
170a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (!TextUtils.isEmpty(countryIso)) {
171a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return new Country(countryIso, Country.COUNTRY_SOURCE_SIM);
172a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
173a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return null;
174a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
175a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
176a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
177a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the country from the system's locale.
178a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
179a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getLocaleCountry() {
180a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Locale defaultLocale = Locale.getDefault();
181a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (defaultLocale != null) {
182a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return new Country(defaultLocale.getCountry(), Country.COUNTRY_SOURCE_LOCALE);
183a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        } else {
184a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return null;
185a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
186a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
187a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
188a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
189a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @param notifyChange indicates whether the listener should be notified the change of the
190a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * country
191a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @param startLocationBasedDetection indicates whether the LocationBasedCountryDetector could
192a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * be started if the current country source is less reliable than the location.
193a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the current available UserCountry
194a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
195a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country detectCountry(boolean notifyChange, boolean startLocationBasedDetection) {
196a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Country country = getCountry();
197a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        runAfterDetectionAsync(mCountry != null ? new Country(mCountry) : mCountry, country,
198a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                notifyChange, startLocationBasedDetection);
199a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mCountry = country;
200a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return mCountry;
201a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
202a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
203a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
204a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Run the tasks in the service's thread.
205a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
206a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected void runAfterDetectionAsync(final Country country, final Country detectedCountry,
207a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            final boolean notifyChange, final boolean startLocationBasedDetection) {
208a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mHandler.post(new Runnable() {
209a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            public void run() {
210a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                runAfterDetection(
211a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                        country, detectedCountry, notifyChange, startLocationBasedDetection);
212a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
213a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        });
214a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
215a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
216a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
217a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public void setCountryListener(CountryListener listener) {
218a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        CountryListener prevListener = mListener;
219a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mListener = listener;
220a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mListener == null) {
221a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Stop listening all services
222a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            removePhoneStateListener();
223a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            stopLocationBasedDetector();
224a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            cancelLocationRefresh();
225a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        } else if (prevListener == null) {
226a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            addPhoneStateListener();
227a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            detectCountry(false, true);
228a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
229a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
230a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
231a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    void runAfterDetection(final Country country, final Country detectedCountry,
232a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            final boolean notifyChange, final boolean startLocationBasedDetection) {
233a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (notifyChange) {
234a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            notifyIfCountryChanged(country, detectedCountry);
235a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
236a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (startLocationBasedDetection && (detectedCountry == null
237a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                || detectedCountry.getSource() > Country.COUNTRY_SOURCE_LOCATION)
238a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                && isAirplaneModeOff() && mListener != null && isGeoCoderImplemented()) {
239a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Start finding location when the source is less reliable than the
240a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // location and the airplane mode is off (as geocoder will not
241a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // work).
242a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // TODO : Shall we give up starting the detector within a
243a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // period of time?
244a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            startLocationBasedDetector(mLocationBasedCountryDetectionListener);
245a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
246a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (detectedCountry == null
247a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                || detectedCountry.getSource() >= Country.COUNTRY_SOURCE_LOCATION) {
248a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Schedule the location refresh if the country source is
249a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // not more reliable than the location or no country is
250a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // found.
251a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // TODO: Listen to the preference change of GPS, Wifi etc,
252a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // and start detecting the country.
253a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            scheduleLocationRefresh();
254a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        } else {
255a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Cancel the location refresh once the current source is
256a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // more reliable than the location.
257a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            cancelLocationRefresh();
258a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            stopLocationBasedDetector();
259a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
260a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
261a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
262a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
263a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Find the country from LocationProvider.
264a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
265a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void startLocationBasedDetector(CountryListener listener) {
266a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationBasedCountryDetector != null) {
267a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return;
268a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
269a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationBasedCountryDetector = createLocationBasedCountryDetector();
270a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationBasedCountryDetector.setCountryListener(listener);
271a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationBasedCountryDetector.detectCountry();
272a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
273a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
274a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void stopLocationBasedDetector() {
275a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationBasedCountryDetector != null) {
276a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationBasedCountryDetector.stop();
277a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationBasedCountryDetector = null;
278a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
279a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
280a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
281a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected CountryDetectorBase createLocationBasedCountryDetector() {
282a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return new LocationBasedCountryDetector(mContext);
283a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
284a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
285a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected boolean isAirplaneModeOff() {
286a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return Settings.System.getInt(
287a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 0;
288a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
289a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
290a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
291a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Notify the country change.
292a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
293a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private void notifyIfCountryChanged(final Country country, final Country detectedCountry) {
294a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (detectedCountry != null && mListener != null
295a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                && (country == null || !country.equals(detectedCountry))) {
296a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            Slog.d(TAG,
297a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    "The country was changed from " + country != null ? country.getCountryIso() :
298a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                        country + " to " + detectedCountry.getCountryIso());
299a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            notifyListener(detectedCountry);
300a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
301a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
302a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
303a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
304a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Schedule the next location refresh. We will do nothing if the scheduled task exists.
305a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
306a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void scheduleLocationRefresh() {
307a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationRefreshTimer != null) return;
308a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationRefreshTimer = new Timer();
309a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationRefreshTimer.schedule(new TimerTask() {
310a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            @Override
311a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            public void run() {
312a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                mLocationRefreshTimer = null;
313a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                detectCountry(false, true);
314a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
315a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }, LOCATION_REFRESH_INTERVAL);
316a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
317a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
318a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
319a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Cancel the scheduled refresh task if it exists
320a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
321a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void cancelLocationRefresh() {
322a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationRefreshTimer != null) {
323a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationRefreshTimer.cancel();
324a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationRefreshTimer = null;
325a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
326a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
327a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
328a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected synchronized void addPhoneStateListener() {
329a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mPhoneStateListener == null && mPhoneType == TelephonyManager.PHONE_TYPE_GSM) {
330a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLastState = null;
331a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mPhoneStateListener = new PhoneStateListener() {
332a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                @Override
333a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                public void onServiceStateChanged(ServiceState serviceState) {
334a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    // TODO: Find out how often we will be notified, if this
335a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    // method is called too
336a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    // many times, let's consider querying the network.
337a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    Slog.d(TAG, "onServiceStateChanged");
338a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    // We only care the state change
339a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    if (mLastState == null || mLastState.getState() != serviceState.getState()) {
340a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                        detectCountry(true, true);
341a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                        mLastState = new ServiceState(serviceState);
342a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    }
343a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                }
344a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            };
345a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
346a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
347a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
348a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
349a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected synchronized void removePhoneStateListener() {
350a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mPhoneStateListener != null) {
351a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
352a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mPhoneStateListener = null;
353a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
354a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
355a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
356a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected boolean isGeoCoderImplemented() {
357a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return Geocoder.isImplemented();
358a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
359a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao}
360