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