CountryDetectorService.java revision 8d044e8bc287c1a567d82aedbe30085b011544c3
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 17package com.android.server; 18 19import java.io.FileDescriptor; 20import java.io.PrintWriter; 21import java.util.HashMap; 22 23import com.android.internal.os.BackgroundThread; 24import com.android.server.location.ComprehensiveCountryDetector; 25 26import android.content.Context; 27import android.location.Country; 28import android.location.CountryListener; 29import android.location.ICountryDetector; 30import android.location.ICountryListener; 31import android.os.Handler; 32import android.os.IBinder; 33import android.os.RemoteException; 34import android.util.PrintWriterPrinter; 35import android.util.Printer; 36import android.util.Slog; 37 38/** 39 * This class detects the country that the user is in through 40 * {@link ComprehensiveCountryDetector}. 41 * 42 * @hide 43 */ 44public class CountryDetectorService extends ICountryDetector.Stub implements Runnable { 45 46 /** 47 * The class represents the remote listener, it will also removes itself 48 * from listener list when the remote process was died. 49 */ 50 private final class Receiver implements IBinder.DeathRecipient { 51 private final ICountryListener mListener; 52 private final IBinder mKey; 53 54 public Receiver(ICountryListener listener) { 55 mListener = listener; 56 mKey = listener.asBinder(); 57 } 58 59 public void binderDied() { 60 removeListener(mKey); 61 } 62 63 @Override 64 public boolean equals(Object otherObj) { 65 if (otherObj instanceof Receiver) { 66 return mKey.equals(((Receiver) otherObj).mKey); 67 } 68 return false; 69 } 70 71 @Override 72 public int hashCode() { 73 return mKey.hashCode(); 74 } 75 76 public ICountryListener getListener() { 77 return mListener; 78 } 79 } 80 81 private final static String TAG = "CountryDetector"; 82 83 /** Whether to dump the state of the country detector service to bugreports */ 84 private static final boolean DEBUG = false; 85 86 private final HashMap<IBinder, Receiver> mReceivers; 87 private final Context mContext; 88 private ComprehensiveCountryDetector mCountryDetector; 89 private boolean mSystemReady; 90 private Handler mHandler; 91 private CountryListener mLocationBasedDetectorListener; 92 93 public CountryDetectorService(Context context) { 94 super(); 95 mReceivers = new HashMap<IBinder, Receiver>(); 96 mContext = context; 97 } 98 99 @Override 100 public Country detectCountry() throws RemoteException { 101 if (!mSystemReady) { 102 throw new RemoteException(); 103 } 104 return mCountryDetector.detectCountry(); 105 } 106 107 /** 108 * Add the ICountryListener into the listener list. 109 */ 110 @Override 111 public void addCountryListener(ICountryListener listener) throws RemoteException { 112 if (!mSystemReady) { 113 throw new RemoteException(); 114 } 115 addListener(listener); 116 } 117 118 /** 119 * Remove the ICountryListener from the listener list. 120 */ 121 @Override 122 public void removeCountryListener(ICountryListener listener) throws RemoteException { 123 if (!mSystemReady) { 124 throw new RemoteException(); 125 } 126 removeListener(listener.asBinder()); 127 } 128 129 private void addListener(ICountryListener listener) { 130 synchronized (mReceivers) { 131 Receiver r = new Receiver(listener); 132 try { 133 listener.asBinder().linkToDeath(r, 0); 134 mReceivers.put(listener.asBinder(), r); 135 if (mReceivers.size() == 1) { 136 Slog.d(TAG, "The first listener is added"); 137 setCountryListener(mLocationBasedDetectorListener); 138 } 139 } catch (RemoteException e) { 140 Slog.e(TAG, "linkToDeath failed:", e); 141 } 142 } 143 } 144 145 private void removeListener(IBinder key) { 146 synchronized (mReceivers) { 147 mReceivers.remove(key); 148 if (mReceivers.isEmpty()) { 149 setCountryListener(null); 150 Slog.d(TAG, "No listener is left"); 151 } 152 } 153 } 154 155 156 protected void notifyReceivers(Country country) { 157 synchronized(mReceivers) { 158 for (Receiver receiver : mReceivers.values()) { 159 try { 160 receiver.getListener().onCountryDetected(country); 161 } catch (RemoteException e) { 162 // TODO: Shall we remove the receiver? 163 Slog.e(TAG, "notifyReceivers failed:", e); 164 } 165 } 166 } 167 } 168 169 void systemReady() { 170 // Shall we wait for the initialization finish. 171 BackgroundThread.getHandler().post(this); 172 } 173 174 private void initialize() { 175 mCountryDetector = new ComprehensiveCountryDetector(mContext); 176 mLocationBasedDetectorListener = new CountryListener() { 177 public void onCountryDetected(final Country country) { 178 mHandler.post(new Runnable() { 179 public void run() { 180 notifyReceivers(country); 181 } 182 }); 183 } 184 }; 185 } 186 187 public void run() { 188 mHandler = new Handler(); 189 initialize(); 190 mSystemReady = true; 191 } 192 193 protected void setCountryListener(final CountryListener listener) { 194 mHandler.post(new Runnable() { 195 @Override 196 public void run() { 197 mCountryDetector.setCountryListener(listener); 198 } 199 }); 200 } 201 202 // For testing 203 boolean isSystemReady() { 204 return mSystemReady; 205 } 206 207 @SuppressWarnings("unused") 208 @Override 209 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 210 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 211 212 if (!DEBUG) return; 213 try { 214 final Printer p = new PrintWriterPrinter(fout); 215 p.println("CountryDetectorService state:"); 216 p.println(" Number of listeners=" + mReceivers.keySet().size()); 217 if (mCountryDetector == null) { 218 p.println(" ComprehensiveCountryDetector not initialized"); 219 } else { 220 p.println(" " + mCountryDetector.toString()); 221 } 222 } catch (Exception e) { 223 Slog.e(TAG, "Failed to dump CountryDetectorService: ", e); 224 } 225 } 226} 227