1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.location; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.Intent; 22import android.content.ServiceConnection; 23import android.location.Criteria; 24import android.location.ILocationProvider; 25import android.location.Location; 26import android.net.NetworkInfo; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.RemoteException; 31import android.os.WorkSource; 32import android.util.Log; 33 34import com.android.internal.location.DummyLocationProvider; 35 36/** 37 * A class for proxying location providers implemented as services. 38 * 39 * {@hide} 40 */ 41public class LocationProviderProxy implements LocationProviderInterface { 42 43 private static final String TAG = "LocationProviderProxy"; 44 45 private final Context mContext; 46 private final String mName; 47 private final Intent mIntent; 48 private final Handler mHandler; 49 private final Object mMutex = new Object(); // synchronizes access to non-final members 50 private Connection mServiceConnection = new Connection(); // never null 51 52 // cached values set by the location manager 53 private boolean mLocationTracking = false; 54 private boolean mEnabled = false; 55 private long mMinTime = -1; 56 private WorkSource mMinTimeSource = new WorkSource(); 57 private int mNetworkState; 58 private NetworkInfo mNetworkInfo; 59 60 // constructor for proxying location providers implemented in a separate service 61 public LocationProviderProxy(Context context, String name, String serviceName, 62 Handler handler) { 63 mContext = context; 64 mName = name; 65 mIntent = new Intent(serviceName); 66 mHandler = handler; 67 mContext.bindService(mIntent, mServiceConnection, 68 Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND 69 | Context.BIND_ALLOW_OOM_MANAGEMENT); 70 } 71 72 /** 73 * When unbundled NetworkLocationService package is updated, we 74 * need to unbind from the old version and re-bind to the new one. 75 */ 76 public void reconnect() { 77 synchronized (mMutex) { 78 mContext.unbindService(mServiceConnection); 79 mServiceConnection = new Connection(); 80 mContext.bindService(mIntent, mServiceConnection, 81 Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND 82 | Context.BIND_ALLOW_OOM_MANAGEMENT); 83 } 84 } 85 86 private class Connection implements ServiceConnection, Runnable { 87 88 private ILocationProvider mProvider; 89 90 // for caching requiresNetwork, requiresSatellite, etc. 91 private DummyLocationProvider mCachedAttributes; // synchronized by mMutex 92 93 public void onServiceConnected(ComponentName className, IBinder service) { 94 synchronized (this) { 95 mProvider = ILocationProvider.Stub.asInterface(service); 96 if (mProvider != null) { 97 mHandler.post(this); 98 } 99 } 100 } 101 102 public void onServiceDisconnected(ComponentName className) { 103 synchronized (this) { 104 mProvider = null; 105 } 106 } 107 108 public synchronized ILocationProvider getProvider() { 109 return mProvider; 110 } 111 112 public synchronized DummyLocationProvider getCachedAttributes() { 113 return mCachedAttributes; 114 } 115 116 public void run() { 117 synchronized (mMutex) { 118 if (mServiceConnection != this) { 119 // This ServiceConnection no longer the one we want to bind to. 120 return; 121 } 122 ILocationProvider provider = getProvider(); 123 if (provider == null) { 124 return; 125 } 126 127 // resend previous values from the location manager if the service has restarted 128 try { 129 if (mEnabled) { 130 provider.enable(); 131 } 132 if (mLocationTracking) { 133 provider.enableLocationTracking(true); 134 } 135 if (mMinTime >= 0) { 136 provider.setMinTime(mMinTime, mMinTimeSource); 137 } 138 if (mNetworkInfo != null) { 139 provider.updateNetworkState(mNetworkState, mNetworkInfo); 140 } 141 } catch (RemoteException e) { 142 } 143 144 // init cache of parameters 145 if (mCachedAttributes == null) { 146 try { 147 mCachedAttributes = new DummyLocationProvider(mName, null); 148 mCachedAttributes.setRequiresNetwork(provider.requiresNetwork()); 149 mCachedAttributes.setRequiresSatellite(provider.requiresSatellite()); 150 mCachedAttributes.setRequiresCell(provider.requiresCell()); 151 mCachedAttributes.setHasMonetaryCost(provider.hasMonetaryCost()); 152 mCachedAttributes.setSupportsAltitude(provider.supportsAltitude()); 153 mCachedAttributes.setSupportsSpeed(provider.supportsSpeed()); 154 mCachedAttributes.setSupportsBearing(provider.supportsBearing()); 155 mCachedAttributes.setPowerRequirement(provider.getPowerRequirement()); 156 mCachedAttributes.setAccuracy(provider.getAccuracy()); 157 } catch (RemoteException e) { 158 mCachedAttributes = null; 159 } 160 } 161 } 162 } 163 }; 164 165 public String getName() { 166 return mName; 167 } 168 169 private DummyLocationProvider getCachedAttributes() { 170 synchronized (mMutex) { 171 return mServiceConnection.getCachedAttributes(); 172 } 173 } 174 175 public boolean requiresNetwork() { 176 DummyLocationProvider cachedAttributes = getCachedAttributes(); 177 if (cachedAttributes != null) { 178 return cachedAttributes.requiresNetwork(); 179 } else { 180 return false; 181 } 182 } 183 184 public boolean requiresSatellite() { 185 DummyLocationProvider cachedAttributes = getCachedAttributes(); 186 if (cachedAttributes != null) { 187 return cachedAttributes.requiresSatellite(); 188 } else { 189 return false; 190 } 191 } 192 193 public boolean requiresCell() { 194 DummyLocationProvider cachedAttributes = getCachedAttributes(); 195 if (cachedAttributes != null) { 196 return cachedAttributes.requiresCell(); 197 } else { 198 return false; 199 } 200 } 201 202 public boolean hasMonetaryCost() { 203 DummyLocationProvider cachedAttributes = getCachedAttributes(); 204 if (cachedAttributes != null) { 205 return cachedAttributes.hasMonetaryCost(); 206 } else { 207 return false; 208 } 209 } 210 211 public boolean supportsAltitude() { 212 DummyLocationProvider cachedAttributes = getCachedAttributes(); 213 if (cachedAttributes != null) { 214 return cachedAttributes.supportsAltitude(); 215 } else { 216 return false; 217 } 218 } 219 220 public boolean supportsSpeed() { 221 DummyLocationProvider cachedAttributes = getCachedAttributes(); 222 if (cachedAttributes != null) { 223 return cachedAttributes.supportsSpeed(); 224 } else { 225 return false; 226 } 227 } 228 229 public boolean supportsBearing() { 230 DummyLocationProvider cachedAttributes = getCachedAttributes(); 231 if (cachedAttributes != null) { 232 return cachedAttributes.supportsBearing(); 233 } else { 234 return false; 235 } 236 } 237 238 public int getPowerRequirement() { 239 DummyLocationProvider cachedAttributes = getCachedAttributes(); 240 if (cachedAttributes != null) { 241 return cachedAttributes.getPowerRequirement(); 242 } else { 243 return -1; 244 } 245 } 246 247 public int getAccuracy() { 248 DummyLocationProvider cachedAttributes = getCachedAttributes(); 249 if (cachedAttributes != null) { 250 return cachedAttributes.getAccuracy(); 251 } else { 252 return -1; 253 } 254 } 255 256 public boolean meetsCriteria(Criteria criteria) { 257 synchronized (mMutex) { 258 ILocationProvider provider = mServiceConnection.getProvider(); 259 if (provider != null) { 260 try { 261 return provider.meetsCriteria(criteria); 262 } catch (RemoteException e) { 263 } 264 } 265 } 266 // default implementation if we lost connection to the provider 267 if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) && 268 (criteria.getAccuracy() < getAccuracy())) { 269 return false; 270 } 271 int criteriaPower = criteria.getPowerRequirement(); 272 if ((criteriaPower != Criteria.NO_REQUIREMENT) && 273 (criteriaPower < getPowerRequirement())) { 274 return false; 275 } 276 if (criteria.isAltitudeRequired() && !supportsAltitude()) { 277 return false; 278 } 279 if (criteria.isSpeedRequired() && !supportsSpeed()) { 280 return false; 281 } 282 if (criteria.isBearingRequired() && !supportsBearing()) { 283 return false; 284 } 285 return true; 286 } 287 288 public void enable() { 289 synchronized (mMutex) { 290 mEnabled = true; 291 ILocationProvider provider = mServiceConnection.getProvider(); 292 if (provider != null) { 293 try { 294 provider.enable(); 295 } catch (RemoteException e) { 296 } 297 } 298 } 299 } 300 301 public void disable() { 302 synchronized (mMutex) { 303 mEnabled = false; 304 ILocationProvider provider = mServiceConnection.getProvider(); 305 if (provider != null) { 306 try { 307 provider.disable(); 308 } catch (RemoteException e) { 309 } 310 } 311 } 312 } 313 314 public boolean isEnabled() { 315 synchronized (mMutex) { 316 return mEnabled; 317 } 318 } 319 320 public int getStatus(Bundle extras) { 321 ILocationProvider provider; 322 synchronized (mMutex) { 323 provider = mServiceConnection.getProvider(); 324 } 325 if (provider != null) { 326 try { 327 return provider.getStatus(extras); 328 } catch (RemoteException e) { 329 } 330 } 331 return 0; 332 } 333 334 public long getStatusUpdateTime() { 335 ILocationProvider provider; 336 synchronized (mMutex) { 337 provider = mServiceConnection.getProvider(); 338 } 339 if (provider != null) { 340 try { 341 return provider.getStatusUpdateTime(); 342 } catch (RemoteException e) { 343 } 344 } 345 return 0; 346 } 347 348 public String getInternalState() { 349 ILocationProvider provider; 350 synchronized (mMutex) { 351 provider = mServiceConnection.getProvider(); 352 } 353 if (provider != null) { 354 try { 355 return provider.getInternalState(); 356 } catch (RemoteException e) { 357 Log.e(TAG, "getInternalState failed", e); 358 } 359 } 360 return null; 361 } 362 363 public boolean isLocationTracking() { 364 synchronized (mMutex) { 365 return mLocationTracking; 366 } 367 } 368 369 public void enableLocationTracking(boolean enable) { 370 synchronized (mMutex) { 371 mLocationTracking = enable; 372 if (!enable) { 373 mMinTime = -1; 374 mMinTimeSource.clear(); 375 } 376 ILocationProvider provider = mServiceConnection.getProvider(); 377 if (provider != null) { 378 try { 379 provider.enableLocationTracking(enable); 380 } catch (RemoteException e) { 381 } 382 } 383 } 384 } 385 386 public boolean requestSingleShotFix() { 387 return false; 388 } 389 390 public long getMinTime() { 391 synchronized (mMutex) { 392 return mMinTime; 393 } 394 } 395 396 public void setMinTime(long minTime, WorkSource ws) { 397 synchronized (mMutex) { 398 mMinTime = minTime; 399 mMinTimeSource.set(ws); 400 ILocationProvider provider = mServiceConnection.getProvider(); 401 if (provider != null) { 402 try { 403 provider.setMinTime(minTime, ws); 404 } catch (RemoteException e) { 405 } 406 } 407 } 408 } 409 410 public void updateNetworkState(int state, NetworkInfo info) { 411 synchronized (mMutex) { 412 mNetworkState = state; 413 mNetworkInfo = info; 414 ILocationProvider provider = mServiceConnection.getProvider(); 415 if (provider != null) { 416 try { 417 provider.updateNetworkState(state, info); 418 } catch (RemoteException e) { 419 } 420 } 421 } 422 } 423 424 public void updateLocation(Location location) { 425 synchronized (mMutex) { 426 ILocationProvider provider = mServiceConnection.getProvider(); 427 if (provider != null) { 428 try { 429 provider.updateLocation(location); 430 } catch (RemoteException e) { 431 } 432 } 433 } 434 } 435 436 public boolean sendExtraCommand(String command, Bundle extras) { 437 synchronized (mMutex) { 438 ILocationProvider provider = mServiceConnection.getProvider(); 439 if (provider != null) { 440 try { 441 return provider.sendExtraCommand(command, extras); 442 } catch (RemoteException e) { 443 } 444 } 445 } 446 return false; 447 } 448 449 public void addListener(int uid) { 450 synchronized (mMutex) { 451 ILocationProvider provider = mServiceConnection.getProvider(); 452 if (provider != null) { 453 try { 454 provider.addListener(uid); 455 } catch (RemoteException e) { 456 } 457 } 458 } 459 } 460 461 public void removeListener(int uid) { 462 synchronized (mMutex) { 463 ILocationProvider provider = mServiceConnection.getProvider(); 464 if (provider != null) { 465 try { 466 provider.removeListener(uid); 467 } catch (RemoteException e) { 468 } 469 } 470 } 471 } 472} 473