FileDocCategorySizeDatePackage
FusionEngine.javaAPI DocAndroid 5.1 API11099Thu Mar 12 22:22:40 GMT 2015com.android.location.fused

FusionEngine

public class FusionEngine extends Object implements android.location.LocationListener

Fields Summary
private static final String
TAG
private static final String
NETWORK
private static final String
GPS
private static final String
FUSED
public static final long
SWITCH_ON_FRESHNESS_CLIFF_NS
private final android.content.Context
mContext
private final android.location.LocationManager
mLocationManager
private final android.os.Looper
mLooper
private Callback
mCallback
private android.location.Location
mFusedLocation
private android.location.Location
mGpsLocation
private android.location.Location
mNetworkLocation
private boolean
mEnabled
private com.android.location.provider.ProviderRequestUnbundled
mRequest
private final HashMap
mStats
Constructors Summary
public FusionEngine(android.content.Context context, android.os.Looper looper)


         
        mContext = context;
        mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        mNetworkLocation = new Location("");
        mNetworkLocation.setAccuracy(Float.MAX_VALUE);
        mGpsLocation = new Location("");
        mGpsLocation.setAccuracy(Float.MAX_VALUE);
        mLooper = looper;

        mStats.put(GPS, new ProviderStats());
        mStats.get(GPS).available = mLocationManager.isProviderEnabled(GPS);
        mStats.put(NETWORK, new ProviderStats());
        mStats.get(NETWORK).available = mLocationManager.isProviderEnabled(NETWORK);

    
Methods Summary
public voiddeinit()
Called to stop doing any work, and release all resources This can happen when a better fusion engine is installed in a different package, and this one is no longer needed. Called on mLooper thread

        mRequest = null;
        disable();
        Log.i(TAG, "engine stopped (" + mContext.getPackageName() + ")");
    
public voiddisable()
Called on mLooper thread

        mEnabled = false;
        updateRequirements();
    
private voiddisableProvider(java.lang.String name)

        ProviderStats stats = mStats.get(name);

        if (stats.requested) {
            stats.requested = false;
            mLocationManager.removeUpdates(this);  //TODO GLOBAL
        }
    
public voiddump(java.io.FileDescriptor fd, java.io.PrintWriter pw, java.lang.String[] args)

        StringBuilder s = new StringBuilder();
        s.append("mEnabled=" + mEnabled).append(' ").append(mRequest).append('\n");
        s.append("fused=").append(mFusedLocation).append('\n");
        s.append(String.format("gps %s\n", mGpsLocation));
        s.append("    ").append(mStats.get(GPS)).append('\n");
        s.append(String.format("net %s\n", mNetworkLocation));
        s.append("    ").append(mStats.get(NETWORK)).append('\n");
        pw.append(s);
    
public voidenable()
Called on mLooper thread

        mEnabled = true;
        updateRequirements();
    
private voidenableProvider(java.lang.String name, long minTime)

        ProviderStats stats = mStats.get(name);

        if (stats.available) {
            if (!stats.requested) {
                stats.requestTime = SystemClock.elapsedRealtime();
                stats.requested = true;
                stats.minTime = minTime;
                mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
            } else if (stats.minTime != minTime) {
                stats.minTime = minTime;
                mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
            }
        }
    
public voidinit(com.android.location.fused.FusionEngine$Callback callback)

        Log.i(TAG, "engine started (" + mContext.getPackageName() + ")");
        mCallback = callback;
    
private static booleanisBetterThan(android.location.Location locationA, android.location.Location locationB)
Test whether one location (a) is better to use than another (b).

      if (locationA == null) {
        return false;
      }
      if (locationB == null) {
        return true;
      }
      // A provider is better if the reading is sufficiently newer.  Heading
      // underground can cause GPS to stop reporting fixes.  In this case it's
      // appropriate to revert to cell, even when its accuracy is less.
      if (locationA.getElapsedRealtimeNanos() > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
        return true;
      }

      // A provider is better if it has better accuracy.  Assuming both readings
      // are fresh (and by that accurate), choose the one with the smaller
      // accuracy circle.
      if (!locationA.hasAccuracy()) {
        return false;
      }
      if (!locationB.hasAccuracy()) {
        return true;
      }
      return locationA.getAccuracy() < locationB.getAccuracy();
    
public voidonLocationChanged(android.location.Location location)
Called on mLooper thread

        if (GPS.equals(location.getProvider())) {
            mGpsLocation = location;
            updateFusedLocation();
        } else if (NETWORK.equals(location.getProvider())) {
            mNetworkLocation = location;
            updateFusedLocation();
        }
    
public voidonProviderDisabled(java.lang.String provider)
Called on mLooper thread

        ProviderStats stats = mStats.get(provider);
        if (stats == null) return;

        stats.available = false;
    
public voidonProviderEnabled(java.lang.String provider)
Called on mLooper thread

        ProviderStats stats = mStats.get(provider);
        if (stats == null) return;

        stats.available = true;
    
public voidonStatusChanged(java.lang.String provider, int status, android.os.Bundle extras)
Called on mLooper thread

  
public voidsetRequest(com.android.location.provider.ProviderRequestUnbundled request, android.os.WorkSource source)
Called on mLooper thread

        mRequest = request;
        mEnabled = request.getReportLocation();
        updateRequirements();
    
public voidswitchUser()
Called on mLooper thread

        // reset state to prevent location data leakage
        mFusedLocation = null;
        mGpsLocation = null;
        mNetworkLocation = null;
    
private voidupdateFusedLocation()

        // may the best location win!
        if (isBetterThan(mGpsLocation, mNetworkLocation)) {
            mFusedLocation = new Location(mGpsLocation);
        } else {
            mFusedLocation = new Location(mNetworkLocation);
        }
        mFusedLocation.setProvider(FUSED);
        if (mNetworkLocation != null) {
            // copy NO_GPS_LOCATION extra from mNetworkLocation into mFusedLocation
            Bundle srcExtras = mNetworkLocation.getExtras();
            if (srcExtras != null) {
                Parcelable srcParcelable =
                        srcExtras.getParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION);
                if (srcParcelable instanceof Location) {
                    Bundle dstExtras = mFusedLocation.getExtras();
                    if (dstExtras == null) {
                        dstExtras = new Bundle();
                        mFusedLocation.setExtras(dstExtras);
                    }
                    dstExtras.putParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION,
                            (Location) srcParcelable);
                }
            }
        }

        if (mCallback != null) {
          mCallback.reportLocation(mFusedLocation);
        } else {
          Log.w(TAG, "Location updates received while fusion engine not started");
        }
    
private voidupdateRequirements()

        if (mEnabled == false || mRequest == null) {
            mRequest = null;
            disableProvider(NETWORK);
            disableProvider(GPS);
            return;
        }

        long networkInterval = Long.MAX_VALUE;
        long gpsInterval = Long.MAX_VALUE;
        for (LocationRequestUnbundled request : mRequest.getLocationRequests()) {
            switch (request.getQuality()) {
                case LocationRequestUnbundled.ACCURACY_FINE:
                case LocationRequestUnbundled.POWER_HIGH:
                    if (request.getInterval() < gpsInterval) {
                        gpsInterval = request.getInterval();
                    }
                    if (request.getInterval() < networkInterval) {
                        networkInterval = request.getInterval();
                    }
                    break;
                case LocationRequestUnbundled.ACCURACY_BLOCK:
                case LocationRequestUnbundled.ACCURACY_CITY:
                case LocationRequestUnbundled.POWER_LOW:
                    if (request.getInterval() < networkInterval) {
                        networkInterval = request.getInterval();
                    }
                    break;
            }
        }

        if (gpsInterval < Long.MAX_VALUE) {
            enableProvider(GPS, gpsInterval);
        } else {
            disableProvider(GPS);
        }
        if (networkInterval < Long.MAX_VALUE) {
            enableProvider(NETWORK, networkInterval);
        } else {
            disableProvider(NETWORK);
        }