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 android.content.Context;
20a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Country;
21a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.CountryListener;
22a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.location.Geocoder;
23d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onukiimport android.os.SystemClock;
24a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.provider.Settings;
25a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.telephony.PhoneStateListener;
26a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.telephony.ServiceState;
27a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.telephony.TelephonyManager;
28a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.text.TextUtils;
29a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taoimport android.util.Slog;
30a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
31141e00c212ab1cd9d6def55edadc3e709d88f9d5Marc Blankimport java.util.Locale;
32141e00c212ab1cd9d6def55edadc3e709d88f9d5Marc Blankimport java.util.Timer;
33141e00c212ab1cd9d6def55edadc3e709d88f9d5Marc Blankimport java.util.TimerTask;
34d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onukiimport java.util.concurrent.ConcurrentLinkedQueue;
35141e00c212ab1cd9d6def55edadc3e709d88f9d5Marc Blank
36a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao/**
37a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * This class is used to detect the country where the user is. The sources of
38a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * country are queried in order of reliability, like
39a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <ul>
40a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>Mobile network</li>
41a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>Location</li>
42a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>SIM's country</li>
43a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <li>Phone's locale</li>
44a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * </ul>
45a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
46a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Call the {@link #detectCountry()} to get the available country immediately.
47a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
48a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * To be notified of the future country change, using the
49a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * {@link #setCountryListener(CountryListener)}
50a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
51a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * Using the {@link #stop()} to stop listening to the country change.
52a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * <p>
53a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * The country information will be refreshed every
54a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * {@link #LOCATION_REFRESH_INTERVAL} once the location based country is used.
55a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao *
56a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao * @hide
57a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao */
58a58a8751b4c2ce457f0082a0baaee61312d56195Bai Taopublic class ComprehensiveCountryDetector extends CountryDetectorBase {
59a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
60d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private final static String TAG = "CountryDetector";
61a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa    /* package */ static final boolean DEBUG = false;
62a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
63a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
64d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Max length of logs to maintain for debugging.
65d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
66d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private static final int MAX_LENGTH_DEBUG_LOGS = 20;
67d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
68d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
69a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * The refresh interval when the location based country was used
70a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
71a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private final static long LOCATION_REFRESH_INTERVAL = 1000 * 60 * 60 * 24; // 1 day
72a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
73a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected CountryDetectorBase mLocationBasedCountryDetector;
74a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Timer mLocationRefreshTimer;
75a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
76a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country mCountry;
77d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private final TelephonyManager mTelephonyManager;
78a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country mCountryFromLocation;
79a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private boolean mStopped = false;
80a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
81d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private PhoneStateListener mPhoneStateListener;
82d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
83d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
84d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * List of the most recent country state changes for debugging. This should have
85d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * a max length of MAX_LENGTH_LOGS.
86d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
87d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private final ConcurrentLinkedQueue<Country> mDebugLogs = new ConcurrentLinkedQueue<Country>();
88d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
89d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
90d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Most recent {@link Country} result that was added to the debug logs {@link #mDebugLogs}.
91d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * We keep track of this value to help prevent adding many of the same {@link Country} objects
92d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * to the logs.
93d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
94d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private Country mLastCountryAddedToLogs;
95d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
96d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
97d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Object used to synchronize access to {@link #mLastCountryAddedToLogs}. Be careful if
98d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * using it to synchronize anything else in this file.
99d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
100d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private final Object mObject = new Object();
101d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
102d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
103d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Start time of the current session for which the detector has been active.
104d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
105d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private long mStartTime;
106d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
107d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
108d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Stop time of the most recent session for which the detector was active.
109d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
110d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private long mStopTime;
111d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
112d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
113d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * The sum of all the time intervals in which the detector was active.
114d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
115d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private long mTotalTime;
116d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
117d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
118d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Number of {@link PhoneStateListener#onServiceStateChanged(ServiceState state)} events that
119d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * have occurred for the current session for which the detector has been active.
120d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
121d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private int mCountServiceStateChanges;
122d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
123d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
124d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Total number of {@link PhoneStateListener#onServiceStateChanged(ServiceState state)} events
125d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * that have occurred for all time intervals in which the detector has been active.
126d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
127d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private int mTotalCountServiceStateChanges;
128a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
129a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
130a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * The listener for receiving the notification from LocationBasedCountryDetector.
131a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
132a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private CountryListener mLocationBasedCountryDetectionListener = new CountryListener() {
133a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        @Override
134a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        public void onCountryDetected(Country country) {
135a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa            if (DEBUG) Slog.d(TAG, "Country detected via LocationBasedCountryDetector");
136a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mCountryFromLocation = country;
137a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Don't start the LocationBasedCountryDetector.
138a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            detectCountry(true, false);
139a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            stopLocationBasedDetector();
140a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
141a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    };
142a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
143a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public ComprehensiveCountryDetector(Context context) {
144a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        super(context);
145a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
146a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
147a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
148a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
149a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public Country detectCountry() {
150a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        // Don't start the LocationBasedCountryDetector if we have been stopped.
151a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return detectCountry(false, !mStopped);
152a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
153a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
154a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
155a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public void stop() {
156d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // Note: this method in this subclass called only by tests.
157a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Slog.i(TAG, "Stop the detector.");
158a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        cancelLocationRefresh();
159a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        removePhoneStateListener();
160a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        stopLocationBasedDetector();
161a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mListener = null;
162a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mStopped = true;
163a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
164a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
165a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
166a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Get the country from different sources in order of the reliability.
167a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
168a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country getCountry() {
169a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Country result = null;
170a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        result = getNetworkBasedCountry();
171a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (result == null) {
172a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            result = getLastKnownLocationBasedCountry();
173a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
174a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (result == null) {
175a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            result = getSimBasedCountry();
176a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
177a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (result == null) {
178a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            result = getLocaleCountry();
179a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
180d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        addToLogs(result);
181a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return result;
182a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
183a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
184a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
185d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     * Attempt to add this {@link Country} to the debug logs.
186d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki     */
187d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private void addToLogs(Country country) {
188d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        if (country == null) {
189d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            return;
190d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        }
191d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // If the country (ISO and source) are the same as before, then there is no
192d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // need to add this country as another entry in the logs. Synchronize access to this
193d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // variable since multiple threads could be calling this method.
194d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        synchronized (mObject) {
195d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            if (mLastCountryAddedToLogs != null && mLastCountryAddedToLogs.equals(country)) {
196d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                return;
197d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            }
198d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            mLastCountryAddedToLogs = country;
199d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        }
200d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // Manually maintain a max limit for the list of logs
201d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        if (mDebugLogs.size() >= MAX_LENGTH_DEBUG_LOGS) {
202d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            mDebugLogs.poll();
203d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        }
2040e87370077b322b3a88c345a44c6bf3d56617071Daniel Lehmann        if (DEBUG) {
205d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            Slog.d(TAG, country.toString());
206d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        }
207d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        mDebugLogs.add(country);
208d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    }
209d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
210d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    private boolean isNetworkCountryCodeAvailable() {
211d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // On CDMA TelephonyManager.getNetworkCountryIso() just returns SIM country.  We don't want
212d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // to prioritize it over location based country, so ignore it.
213d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        final int phoneType = mTelephonyManager.getPhoneType();
214d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        if (DEBUG) Slog.v(TAG, "    phonetype=" + phoneType);
215d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        return phoneType == TelephonyManager.PHONE_TYPE_GSM;
216d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    }
217d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
218d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    /**
219a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the country from the mobile network.
220a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
221a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getNetworkBasedCountry() {
222a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        String countryIso = null;
223d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        if (isNetworkCountryCodeAvailable()) {
224a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            countryIso = mTelephonyManager.getNetworkCountryIso();
225a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            if (!TextUtils.isEmpty(countryIso)) {
226a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                return new Country(countryIso, Country.COUNTRY_SOURCE_NETWORK);
227a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
228a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
229a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return null;
230a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
231a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
232a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
233a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the cached location based country.
234a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
235a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getLastKnownLocationBasedCountry() {
236a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return mCountryFromLocation;
237a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
238a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
239a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
240a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the country from SIM card
241a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
242a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getSimBasedCountry() {
243a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        String countryIso = null;
244a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        countryIso = mTelephonyManager.getSimCountryIso();
245a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (!TextUtils.isEmpty(countryIso)) {
246a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return new Country(countryIso, Country.COUNTRY_SOURCE_SIM);
247a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
248a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return null;
249a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
250a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
251a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
252a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the country from the system's locale.
253a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
254a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected Country getLocaleCountry() {
255a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Locale defaultLocale = Locale.getDefault();
256a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (defaultLocale != null) {
257a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return new Country(defaultLocale.getCountry(), Country.COUNTRY_SOURCE_LOCALE);
258a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        } else {
259a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return null;
260a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
261a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
262a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
263a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
264a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @param notifyChange indicates whether the listener should be notified the change of the
265a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * country
266a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @param startLocationBasedDetection indicates whether the LocationBasedCountryDetector could
267a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * be started if the current country source is less reliable than the location.
268a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * @return the current available UserCountry
269a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
270a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private Country detectCountry(boolean notifyChange, boolean startLocationBasedDetection) {
271a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        Country country = getCountry();
272a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        runAfterDetectionAsync(mCountry != null ? new Country(mCountry) : mCountry, country,
273a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                notifyChange, startLocationBasedDetection);
274a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mCountry = country;
275a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return mCountry;
276a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
277a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
278a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
279a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Run the tasks in the service's thread.
280a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
281a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected void runAfterDetectionAsync(final Country country, final Country detectedCountry,
282a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            final boolean notifyChange, final boolean startLocationBasedDetection) {
283a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mHandler.post(new Runnable() {
284a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa            @Override
285a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            public void run() {
286a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                runAfterDetection(
287a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                        country, detectedCountry, notifyChange, startLocationBasedDetection);
288a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
289a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        });
290a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
291a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
292a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    @Override
293a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    public void setCountryListener(CountryListener listener) {
294a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        CountryListener prevListener = mListener;
295a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mListener = listener;
296a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mListener == null) {
297a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Stop listening all services
298a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            removePhoneStateListener();
299a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            stopLocationBasedDetector();
300a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            cancelLocationRefresh();
301d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            mStopTime = SystemClock.elapsedRealtime();
302d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            mTotalTime += mStopTime;
303a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        } else if (prevListener == null) {
304a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            addPhoneStateListener();
305a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            detectCountry(false, true);
306d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            mStartTime = SystemClock.elapsedRealtime();
307d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            mStopTime = 0;
308d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            mCountServiceStateChanges = 0;
309a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
310a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
311a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
312a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    void runAfterDetection(final Country country, final Country detectedCountry,
313a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            final boolean notifyChange, final boolean startLocationBasedDetection) {
314a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (notifyChange) {
315a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            notifyIfCountryChanged(country, detectedCountry);
316a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
317a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        if (DEBUG) {
318a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa            Slog.d(TAG, "startLocationBasedDetection=" + startLocationBasedDetection
319a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    + " detectCountry=" + (detectedCountry == null ? null :
320a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                        "(source: " + detectedCountry.getSource()
321a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                        + ", countryISO: " + detectedCountry.getCountryIso() + ")")
322a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    + " isAirplaneModeOff()=" + isAirplaneModeOff()
323a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    + " mListener=" + mListener
324a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    + " isGeoCoderImplemnted()=" + isGeoCoderImplemented());
325a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        }
326a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa
327a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (startLocationBasedDetection && (detectedCountry == null
328a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                || detectedCountry.getSource() > Country.COUNTRY_SOURCE_LOCATION)
329a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                && isAirplaneModeOff() && mListener != null && isGeoCoderImplemented()) {
330a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa            if (DEBUG) Slog.d(TAG, "run startLocationBasedDetector()");
331a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Start finding location when the source is less reliable than the
332a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // location and the airplane mode is off (as geocoder will not
333a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // work).
334a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // TODO : Shall we give up starting the detector within a
335a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // period of time?
336a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            startLocationBasedDetector(mLocationBasedCountryDetectionListener);
337a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
338a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (detectedCountry == null
339a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                || detectedCountry.getSource() >= Country.COUNTRY_SOURCE_LOCATION) {
340a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Schedule the location refresh if the country source is
341a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // not more reliable than the location or no country is
342a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // found.
343a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // TODO: Listen to the preference change of GPS, Wifi etc,
344a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // and start detecting the country.
345a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            scheduleLocationRefresh();
346a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        } else {
347a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // Cancel the location refresh once the current source is
348a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            // more reliable than the location.
349a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            cancelLocationRefresh();
350a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            stopLocationBasedDetector();
351a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
352a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
353a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
354a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
355a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Find the country from LocationProvider.
356a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
357a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void startLocationBasedDetector(CountryListener listener) {
358a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationBasedCountryDetector != null) {
359a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            return;
360a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
361a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        if (DEBUG) {
362a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa            Slog.d(TAG, "starts LocationBasedDetector to detect Country code via Location info "
363a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    + "(e.g. GPS)");
364a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        }
365a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationBasedCountryDetector = createLocationBasedCountryDetector();
366a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationBasedCountryDetector.setCountryListener(listener);
367a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationBasedCountryDetector.detectCountry();
368a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
369a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
370a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void stopLocationBasedDetector() {
371a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        if (DEBUG) {
372a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa            Slog.d(TAG, "tries to stop LocationBasedDetector "
373a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    + "(current detector: " + mLocationBasedCountryDetector + ")");
374a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        }
375a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationBasedCountryDetector != null) {
376a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationBasedCountryDetector.stop();
377a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationBasedCountryDetector = null;
378a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
379a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
380a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
381a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected CountryDetectorBase createLocationBasedCountryDetector() {
382a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        return new LocationBasedCountryDetector(mContext);
383a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
384a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
385a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected boolean isAirplaneModeOff() {
386c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate        return Settings.Global.getInt(
387c09cdce1b05075da808ae080b9905a14a3e1e627Christopher Tate                mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 0;
388a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
389a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
390a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
391a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Notify the country change.
392a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
393a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private void notifyIfCountryChanged(final Country country, final Country detectedCountry) {
394a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (detectedCountry != null && mListener != null
395a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                && (country == null || !country.equals(detectedCountry))) {
3960e87370077b322b3a88c345a44c6bf3d56617071Daniel Lehmann            if (DEBUG) {
397d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                Slog.d(TAG, "" + country + " --> " + detectedCountry);
398d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            }
399a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            notifyListener(detectedCountry);
400a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
401a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
402a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
403a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
404a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Schedule the next location refresh. We will do nothing if the scheduled task exists.
405a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
406a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void scheduleLocationRefresh() {
407a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationRefreshTimer != null) return;
408a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        if (DEBUG) {
409a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa            Slog.d(TAG, "start periodic location refresh timer. Interval: "
410a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    + LOCATION_REFRESH_INTERVAL);
411a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa        }
412a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationRefreshTimer = new Timer();
413a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        mLocationRefreshTimer.schedule(new TimerTask() {
414a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            @Override
415a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            public void run() {
416a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                if (DEBUG) {
417a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                    Slog.d(TAG, "periodic location refresh event. Starts detecting Country code");
418a550bdc84af70babb48091197bfb1b93d3671664Daisuke Miyakawa                }
419a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                mLocationRefreshTimer = null;
420a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                detectCountry(false, true);
421a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            }
422a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }, LOCATION_REFRESH_INTERVAL);
423a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
424a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
425a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    /**
426a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     * Cancel the scheduled refresh task if it exists
427a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao     */
428a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    private synchronized void cancelLocationRefresh() {
429a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mLocationRefreshTimer != null) {
430a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationRefreshTimer.cancel();
431a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mLocationRefreshTimer = null;
432a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
433a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
434a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
435a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected synchronized void addPhoneStateListener() {
436d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        if (mPhoneStateListener == null) {
437a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mPhoneStateListener = new PhoneStateListener() {
438a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                @Override
439a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                public void onServiceStateChanged(ServiceState serviceState) {
440d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                    mCountServiceStateChanges++;
441d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                    mTotalCountServiceStateChanges++;
442d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
443d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                    if (!isNetworkCountryCodeAvailable()) {
444d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                        return;
445a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                    }
446d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                    if (DEBUG) Slog.d(TAG, "onServiceStateChanged: " + serviceState.getState());
447d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
448d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki                    detectCountry(true, true);
449a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao                }
450a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            };
451a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
452a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
453a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
454a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
455a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected synchronized void removePhoneStateListener() {
456a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        if (mPhoneStateListener != null) {
457a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
458a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao            mPhoneStateListener = null;
459a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao        }
460a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
461a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao
462a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    protected boolean isGeoCoderImplemented() {
463141e00c212ab1cd9d6def55edadc3e709d88f9d5Marc Blank        return Geocoder.isPresent();
464a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao    }
465d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki
466d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    @Override
467d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    public String toString() {
468d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        long currentTime = SystemClock.elapsedRealtime();
469d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        long currentSessionLength = 0;
470d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        StringBuilder sb = new StringBuilder();
471d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        sb.append("ComprehensiveCountryDetector{");
472d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        // The detector hasn't stopped yet --> still running
473d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        if (mStopTime == 0) {
474d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            currentSessionLength = currentTime - mStartTime;
475d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            sb.append("timeRunning=" + currentSessionLength + ", ");
476d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        } else {
477d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            // Otherwise, it has already stopped, so take the last session
478d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            sb.append("lastRunTimeLength=" + (mStopTime - mStartTime) + ", ");
479d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        }
480d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        sb.append("totalCountServiceStateChanges=" + mTotalCountServiceStateChanges + ", ");
481d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        sb.append("currentCountServiceStateChanges=" + mCountServiceStateChanges + ", ");
482d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        sb.append("totalTime=" + (mTotalTime + currentSessionLength) + ", ");
483d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        sb.append("currentTime=" + currentTime + ", ");
484d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        sb.append("countries=");
485d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        for (Country country : mDebugLogs) {
486d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki            sb.append("\n   " + country.toString());
487d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        }
488d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        sb.append("}");
489d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki        return sb.toString();
490d73b79bb314dde86cf8ff9300fefc133b31841d1Makoto Onuki    }
491a58a8751b4c2ce457f0082a0baaee61312d56195Bai Tao}
492