Home | History | Annotate | Download | only in location
      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 
     17 package com.android.server.location;
     18 
     19 import android.content.ComponentName;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.ServiceConnection;
     23 import android.location.Criteria;
     24 import android.location.ILocationProvider;
     25 import android.location.Location;
     26 import android.net.NetworkInfo;
     27 import android.os.Bundle;
     28 import android.os.Handler;
     29 import android.os.IBinder;
     30 import android.os.RemoteException;
     31 import android.os.WorkSource;
     32 import android.util.Log;
     33 
     34 import com.android.internal.location.DummyLocationProvider;
     35 
     36 /**
     37  * A class for proxying location providers implemented as services.
     38  *
     39  * {@hide}
     40  */
     41 public 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