1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package android.location;
18 
19 import java.util.HashMap;
20 
21 import android.annotation.SystemService;
22 import android.content.Context;
23 import android.os.Handler;
24 import android.os.Looper;
25 import android.os.RemoteException;
26 import android.util.Log;
27 
28 /**
29  * This class provides access to the system country detector service. This
30  * service allows applications to obtain the country that the user is in.
31  * <p>
32  * The country will be detected in order of reliability, like
33  * <ul>
34  * <li>Mobile network</li>
35  * <li>Location</li>
36  * <li>SIM's country</li>
37  * <li>Phone's locale</li>
38  * </ul>
39  * <p>
40  * Call the {@link #detectCountry()} to get the available country immediately.
41  * <p>
42  * To be notified of the future country change, use the
43  * {@link #addCountryListener}
44  * <p>
45  *
46  * @hide
47  */
48 @SystemService(Context.COUNTRY_DETECTOR)
49 public class CountryDetector {
50 
51     /**
52      * The class to wrap the ICountryListener.Stub and CountryListener objects
53      * together. The CountryListener will be notified through the specific
54      * looper once the country changed and detected.
55      */
56     private final static class ListenerTransport extends ICountryListener.Stub {
57 
58         private final CountryListener mListener;
59 
60         private final Handler mHandler;
61 
ListenerTransport(CountryListener listener, Looper looper)62         public ListenerTransport(CountryListener listener, Looper looper) {
63             mListener = listener;
64             if (looper != null) {
65                 mHandler = new Handler(looper);
66             } else {
67                 mHandler = new Handler();
68             }
69         }
70 
onCountryDetected(final Country country)71         public void onCountryDetected(final Country country) {
72             mHandler.post(new Runnable() {
73                 public void run() {
74                     mListener.onCountryDetected(country);
75                 }
76             });
77         }
78     }
79 
80     private final static String TAG = "CountryDetector";
81     private final ICountryDetector mService;
82     private final HashMap<CountryListener, ListenerTransport> mListeners;
83 
84     /**
85      * @hide - hide this constructor because it has a parameter of type
86      *       ICountryDetector, which is a system private class. The right way to
87      *       create an instance of this class is using the factory
88      *       Context.getSystemService.
89      */
CountryDetector(ICountryDetector service)90     public CountryDetector(ICountryDetector service) {
91         mService = service;
92         mListeners = new HashMap<CountryListener, ListenerTransport>();
93     }
94 
95     /**
96      * Start detecting the country that the user is in.
97      *
98      * @return the country if it is available immediately, otherwise null will
99      *         be returned.
100      */
detectCountry()101     public Country detectCountry() {
102         try {
103             return mService.detectCountry();
104         } catch (RemoteException e) {
105             Log.e(TAG, "detectCountry: RemoteException", e);
106             return null;
107         }
108     }
109 
110     /**
111      * Add a listener to receive the notification when the country is detected
112      * or changed.
113      *
114      * @param listener will be called when the country is detected or changed.
115      * @param looper a Looper object whose message queue will be used to
116      *        implement the callback mechanism. If looper is null then the
117      *        callbacks will be called on the main thread.
118      */
addCountryListener(CountryListener listener, Looper looper)119     public void addCountryListener(CountryListener listener, Looper looper) {
120         synchronized (mListeners) {
121             if (!mListeners.containsKey(listener)) {
122                 ListenerTransport transport = new ListenerTransport(listener, looper);
123                 try {
124                     mService.addCountryListener(transport);
125                     mListeners.put(listener, transport);
126                 } catch (RemoteException e) {
127                     Log.e(TAG, "addCountryListener: RemoteException", e);
128                 }
129             }
130         }
131     }
132 
133     /**
134      * Remove the listener
135      */
removeCountryListener(CountryListener listener)136     public void removeCountryListener(CountryListener listener) {
137         synchronized (mListeners) {
138             ListenerTransport transport = mListeners.get(listener);
139             if (transport != null) {
140                 try {
141                     mListeners.remove(listener);
142                     mService.removeCountryListener(transport);
143                 } catch (RemoteException e) {
144                     Log.e(TAG, "removeCountryListener: RemoteException", e);
145                 }
146             }
147         }
148     }
149 }
150