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 android.annotation.SystemService; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.content.Context; 22 import android.os.Build; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.os.RemoteException; 26 import android.util.Log; 27 28 import java.util.HashMap; 29 30 /** 31 * This class provides access to the system country detector service. This 32 * service allows applications to obtain the country that the user is in. 33 * <p> 34 * The country will be detected in order of reliability, like 35 * <ul> 36 * <li>Mobile network</li> 37 * <li>Location</li> 38 * <li>SIM's country</li> 39 * <li>Phone's locale</li> 40 * </ul> 41 * <p> 42 * Call the {@link #detectCountry()} to get the available country immediately. 43 * <p> 44 * To be notified of the future country change, use the 45 * {@link #addCountryListener} 46 * <p> 47 * 48 * @hide 49 */ 50 @SystemService(Context.COUNTRY_DETECTOR) 51 public class CountryDetector { 52 53 /** 54 * The class to wrap the ICountryListener.Stub and CountryListener objects 55 * together. The CountryListener will be notified through the specific 56 * looper once the country changed and detected. 57 */ 58 private final static class ListenerTransport extends ICountryListener.Stub { 59 60 private final CountryListener mListener; 61 62 private final Handler mHandler; 63 ListenerTransport(CountryListener listener, Looper looper)64 public ListenerTransport(CountryListener listener, Looper looper) { 65 mListener = listener; 66 if (looper != null) { 67 mHandler = new Handler(looper); 68 } else { 69 mHandler = new Handler(); 70 } 71 } 72 onCountryDetected(final Country country)73 public void onCountryDetected(final Country country) { 74 mHandler.post(new Runnable() { 75 public void run() { 76 mListener.onCountryDetected(country); 77 } 78 }); 79 } 80 } 81 82 private final static String TAG = "CountryDetector"; 83 private final ICountryDetector mService; 84 private final HashMap<CountryListener, ListenerTransport> mListeners; 85 86 /** 87 * @hide - hide this constructor because it has a parameter of type 88 * ICountryDetector, which is a system private class. The right way to 89 * create an instance of this class is using the factory 90 * Context.getSystemService. 91 */ 92 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) CountryDetector(ICountryDetector service)93 public CountryDetector(ICountryDetector service) { 94 mService = service; 95 mListeners = new HashMap<CountryListener, ListenerTransport>(); 96 } 97 98 /** 99 * Start detecting the country that the user is in. 100 * 101 * @return the country if it is available immediately, otherwise null will 102 * be returned. 103 */ 104 @UnsupportedAppUsage detectCountry()105 public Country detectCountry() { 106 try { 107 return mService.detectCountry(); 108 } catch (RemoteException e) { 109 Log.e(TAG, "detectCountry: RemoteException", e); 110 return null; 111 } 112 } 113 114 /** 115 * Add a listener to receive the notification when the country is detected 116 * or changed. 117 * 118 * @param listener will be called when the country is detected or changed. 119 * @param looper a Looper object whose message queue will be used to 120 * implement the callback mechanism. If looper is null then the 121 * callbacks will be called on the main thread. 122 */ 123 @UnsupportedAppUsage addCountryListener(CountryListener listener, Looper looper)124 public void addCountryListener(CountryListener listener, Looper looper) { 125 synchronized (mListeners) { 126 if (!mListeners.containsKey(listener)) { 127 ListenerTransport transport = new ListenerTransport(listener, looper); 128 try { 129 mService.addCountryListener(transport); 130 mListeners.put(listener, transport); 131 } catch (RemoteException e) { 132 Log.e(TAG, "addCountryListener: RemoteException", e); 133 } 134 } 135 } 136 } 137 138 /** 139 * Remove the listener 140 */ 141 @UnsupportedAppUsage removeCountryListener(CountryListener listener)142 public void removeCountryListener(CountryListener listener) { 143 synchronized (mListeners) { 144 ListenerTransport transport = mListeners.get(listener); 145 if (transport != null) { 146 try { 147 mListeners.remove(listener); 148 mService.removeCountryListener(transport); 149 } catch (RemoteException e) { 150 Log.e(TAG, "removeCountryListener: RemoteException", e); 151 } 152 } 153 } 154 } 155 } 156