FusionEngine.java revision 161f42619b82995f88f6e299b6c74cb8382c4135
16fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly/*
26fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * Copyright (C) 2012 The Android Open Source Project
36fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *
46fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
56fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * you may not use this file except in compliance with the License.
66fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * You may obtain a copy of the License at
76fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *
86fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
96fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly *
106fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * Unless required by applicable law or agreed to in writing, software
116fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
126fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * See the License for the specific language governing permissions and
146fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly * limitations under the License.
156fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly */
166fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
176fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellypackage com.android.location.fused;
186fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
196fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport java.io.FileDescriptor;
206fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport java.io.PrintWriter;
216fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport java.util.HashMap;
226fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
23779b77455fc51382ecafa210b8a805d2a616da55Victoria Leaseimport com.android.location.provider.LocationProviderBase;
247ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tuimport com.android.location.provider.LocationRequestUnbundled;
256fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport com.android.location.provider.ProviderRequestUnbundled;
266fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
276fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.content.Context;
286fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.location.Location;
296fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.location.LocationListener;
306fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.location.LocationManager;
316fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.os.Bundle;
326fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.os.Looper;
33779b77455fc51382ecafa210b8a805d2a616da55Victoria Leaseimport android.os.Parcelable;
346fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.os.SystemClock;
356fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.os.WorkSource;
366fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.util.Log;
376fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
386fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellypublic class FusionEngine implements LocationListener {
396fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public interface Callback {
406fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public void reportLocation(Location location);
416fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
426fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
436fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static final String TAG = "FusedLocation";
446fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static final String NETWORK = LocationManager.NETWORK_PROVIDER;
456fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static final String GPS = LocationManager.GPS_PROVIDER;
46779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease    private static final String FUSED = LocationProviderBase.FUSED_PROVIDER;
476fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
480fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease    public static final long SWITCH_ON_FRESHNESS_CLIFF_NS = 11 * 1000000000; // 11 seconds
496fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
506fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final Context mContext;
516fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final LocationManager mLocationManager;
526fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final Looper mLooper;
536fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
546fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    // all fields are only used on mLooper thread. except for in dump() which is not thread-safe
556fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private Callback mCallback;
566fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private Location mFusedLocation;
576fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private Location mGpsLocation;
586fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private Location mNetworkLocation;
596fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
606fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private boolean mEnabled;
616fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private ProviderRequestUnbundled mRequest;
626fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
636fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private final HashMap<String, ProviderStats> mStats = new HashMap<String, ProviderStats>();
646fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
656fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public FusionEngine(Context context, Looper looper) {
666fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mContext = context;
676fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
686fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mNetworkLocation = new Location("");
696fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mNetworkLocation.setAccuracy(Float.MAX_VALUE);
706fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mGpsLocation = new Location("");
716fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mGpsLocation.setAccuracy(Float.MAX_VALUE);
726fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mLooper = looper;
736fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
746fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mStats.put(GPS, new ProviderStats());
756fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mStats.get(GPS).available = mLocationManager.isProviderEnabled(GPS);
766fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mStats.put(NETWORK, new ProviderStats());
776fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mStats.get(NETWORK).available = mLocationManager.isProviderEnabled(NETWORK);
78779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease
796fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
806fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
816fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void init(Callback callback) {
826fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        Log.i(TAG, "engine started (" + mContext.getPackageName() + ")");
836fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mCallback = callback;
846fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
856fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
866fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /**
876fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     * Called to stop doing any work, and release all resources
886fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     * This can happen when a better fusion engine is installed
896fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     * in a different package, and this one is no longer needed.
906fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     * Called on mLooper thread
916fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly     */
926fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void deinit() {
936fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mRequest = null;
946fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        disable();
956fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        Log.i(TAG, "engine stopped (" + mContext.getPackageName() + ")");
966fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
976fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
986fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** Called on mLooper thread */
996fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void enable() {
1006fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mEnabled = true;
1016fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        updateRequirements();
1026fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1036fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1046fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** Called on mLooper thread */
1056fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void disable() {
1066fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mEnabled = false;
1076fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        updateRequirements();
1086fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1096fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1106fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** Called on mLooper thread */
11108ca1046fe4f1890f91241f8d082a024ef6cfd93Nick Pelly    public void setRequest(ProviderRequestUnbundled request, WorkSource source) {
1126fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        mRequest = request;
11308ca1046fe4f1890f91241f8d082a024ef6cfd93Nick Pelly        mEnabled = request.getReportLocation();
1146fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        updateRequirements();
1156fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1166fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1176fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private static class ProviderStats {
1186fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public boolean available;
1196fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public boolean requested;
1206fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public long requestTime;
1216fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public long minTime;
1226fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        @Override
1236fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        public String toString() {
1246fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            StringBuilder s = new StringBuilder();
1256fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            s.append(available ? "AVAILABLE" : "UNAVAILABLE");
1266fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            s.append(requested ? " REQUESTED" : " ---");
1276fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return s.toString();
1286fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1296fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1306fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1316fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private void enableProvider(String name, long minTime) {
1326fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        ProviderStats stats = mStats.get(name);
1336fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1346fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (!stats.requested) {
1356fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            stats.requestTime = SystemClock.elapsedRealtime();
1366fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            stats.requested = true;
1376fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            stats.minTime = minTime;
1386fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
1396fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        } else if (stats.minTime != minTime) {
1406fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            stats.minTime = minTime;
1416fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
1426fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1436fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1446fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1456fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private void disableProvider(String name) {
1466fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        ProviderStats stats = mStats.get(name);
1476fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1486fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (stats.requested) {
1496fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            stats.requested = false;
1506fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            mLocationManager.removeUpdates(this);  //TODO GLOBAL
1516fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1526fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1536fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1546fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private void updateRequirements() {
1556fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (mEnabled == false || mRequest == null) {
1566fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            mRequest = null;
1576fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            disableProvider(NETWORK);
1586fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            disableProvider(GPS);
1596fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            return;
1606fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1616fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1626fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        long networkInterval = Long.MAX_VALUE;
1636fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        long gpsInterval = Long.MAX_VALUE;
1647ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu        for (LocationRequestUnbundled request : mRequest.getLocationRequests()) {
1656fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            switch (request.getQuality()) {
1667ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu                case LocationRequestUnbundled.ACCURACY_FINE:
1677ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu                case LocationRequestUnbundled.POWER_HIGH:
1686fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    if (request.getInterval() < gpsInterval) {
1696fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                        gpsInterval = request.getInterval();
1706fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    }
1716fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    if (request.getInterval() < networkInterval) {
1726fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                        networkInterval = request.getInterval();
1736fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    }
1746fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    break;
1757ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu                case LocationRequestUnbundled.ACCURACY_BLOCK:
1767ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu                case LocationRequestUnbundled.ACCURACY_CITY:
1777ab7f538924371a9dd4be7a27a6ae3b4c04b301cLaurent Tu                case LocationRequestUnbundled.POWER_LOW:
1786fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    if (request.getInterval() < networkInterval) {
1796fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                        networkInterval = request.getInterval();
1806fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    }
1816fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly                    break;
1826fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            }
1836fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1846fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1856fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (gpsInterval < Long.MAX_VALUE) {
1866fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            enableProvider(GPS, gpsInterval);
1876fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        } else {
1886fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            disableProvider(GPS);
1896fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1906fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (networkInterval < Long.MAX_VALUE) {
1916fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            enableProvider(NETWORK, networkInterval);
1926fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        } else {
1936fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            disableProvider(NETWORK);
1946fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
1956fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
1966fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
1970fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease    /**
1980fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease     * Test whether one location (a) is better to use than another (b).
1990fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease     */
2000fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease    private static boolean isBetterThan(Location locationA, Location locationB) {
2010fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      if (locationA == null) {
2020fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        return false;
2030fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      }
2040fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      if (locationB == null) {
2050fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        return true;
2060fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      }
2070fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      // A provider is better if the reading is sufficiently newer.  Heading
2080fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      // underground can cause GPS to stop reporting fixes.  In this case it's
2090fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      // appropriate to revert to cell, even when its accuracy is less.
2100fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      if (locationA.getElapsedRealtimeNanos() > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
2110fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        return true;
2120fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      }
2130fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease
2140fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      // A provider is better if it has better accuracy.  Assuming both readings
2150fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      // are fresh (and by that accurate), choose the one with the smaller
2160fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      // accuracy circle.
2170fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      if (!locationA.hasAccuracy()) {
2180fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        return false;
2190fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      }
2200fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      if (!locationB.hasAccuracy()) {
2210fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        return true;
2220fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      }
2230fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease      return locationA.getAccuracy() < locationB.getAccuracy();
2246fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
2256fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2266fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    private void updateFusedLocation() {
2270fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        // may the best location win!
2280fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        if (isBetterThan(mGpsLocation, mNetworkLocation)) {
2290fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease            mFusedLocation = new Location(mGpsLocation);
2300fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        } else {
2310fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease            mFusedLocation = new Location(mNetworkLocation);
2326fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
233779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease        mFusedLocation.setProvider(FUSED);
23409016ab4dd056a16809419d612cb865a14980880Victoria Lease        if (mNetworkLocation != null) {
235779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease            // copy NO_GPS_LOCATION extra from mNetworkLocation into mFusedLocation
236779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease            Bundle srcExtras = mNetworkLocation.getExtras();
237779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease            if (srcExtras != null) {
238779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                Parcelable srcParcelable =
239779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                        srcExtras.getParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION);
240779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                if (srcParcelable instanceof Location) {
241779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                    Bundle dstExtras = mFusedLocation.getExtras();
242779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                    if (dstExtras == null) {
243779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                        dstExtras = new Bundle();
244779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                        mFusedLocation.setExtras(dstExtras);
245779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                    }
246779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                    dstExtras.putParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION,
247779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                            (Location) srcParcelable);
248779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease                }
249779b77455fc51382ecafa210b8a805d2a616da55Victoria Lease            }
25009016ab4dd056a16809419d612cb865a14980880Victoria Lease        }
2516fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
252161f42619b82995f88f6e299b6c74cb8382c4135Laurent Tu        if (mCallback != null) {
253161f42619b82995f88f6e299b6c74cb8382c4135Laurent Tu          mCallback.reportLocation(mFusedLocation);
254161f42619b82995f88f6e299b6c74cb8382c4135Laurent Tu        } else {
255161f42619b82995f88f6e299b6c74cb8382c4135Laurent Tu          Log.w(TAG, "Location updates received while fusion engine not started");
256161f42619b82995f88f6e299b6c74cb8382c4135Laurent Tu        }
2576fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
2586fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2596fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** Called on mLooper thread */
2606fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
2616fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void onLocationChanged(Location location) {
2626fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (GPS.equals(location.getProvider())) {
2636fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            mGpsLocation = location;
2646fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            updateFusedLocation();
2656fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        } else if (NETWORK.equals(location.getProvider())) {
2666fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            mNetworkLocation = location;
2676fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly            updateFusedLocation();
2686fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        }
2696fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
2706fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2716fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** Called on mLooper thread */
2726fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
2736fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void onStatusChanged(String provider, int status, Bundle extras) {  }
2746fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2756fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** Called on mLooper thread */
2766fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
2776fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void onProviderEnabled(String provider) {
2786fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        ProviderStats stats = mStats.get(provider);
2796fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (stats == null) return;
2806fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2816fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        stats.available = true;
2826fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
2836fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2846fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    /** Called on mLooper thread */
2856fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    @Override
2866fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void onProviderDisabled(String provider) {
2876fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        ProviderStats stats = mStats.get(provider);
2886fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        if (stats == null) return;
2896fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2906fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        stats.available = false;
2916fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
2926fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly
2936fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2946fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        StringBuilder s = new StringBuilder();
2956fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        s.append("mEnabled=" + mEnabled).append(' ').append(mRequest).append('\n');
2966fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        s.append("fused=").append(mFusedLocation).append('\n');
2970fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        s.append(String.format("gps %s\n", mGpsLocation));
2986fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        s.append("    ").append(mStats.get(GPS)).append('\n');
2990fdfa6b49e7642a90a1b98881e4e2801cbcd3c77Victoria Lease        s.append(String.format("net %s\n", mNetworkLocation));
3006fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        s.append("    ").append(mStats.get(NETWORK)).append('\n');
3016fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly        pw.append(s);
3026fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly    }
3036fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly}
304