1/*
2 * Copyright (C) 2013 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.camera.app;
18
19import android.content.Context;
20import android.location.Location;
21import android.os.Bundle;
22
23import com.android.camera.debug.Log;
24import com.android.camera.util.AndroidServices;
25
26/**
27 * A class that handles legacy (network, gps) location providers, in the event
28 * the fused location provider from Google Play Services is unavailable.
29 */
30public class LegacyLocationProvider implements LocationProvider {
31    private static final Log.Tag TAG = new Log.Tag("LcyLocProvider");
32
33    private Context mContext;
34    private android.location.LocationManager mLocationManager;
35    private boolean mRecordLocation;
36
37    LocationListener [] mLocationListeners = new LocationListener[] {
38            new LocationListener(android.location.LocationManager.GPS_PROVIDER),
39            new LocationListener(android.location.LocationManager.NETWORK_PROVIDER)
40    };
41
42    public LegacyLocationProvider(Context context) {
43        mContext = context;
44    }
45
46    @Override
47    public Location getCurrentLocation() {
48        if (!mRecordLocation) {
49            return null;
50        }
51
52        // go in best to worst order
53        for (int i = 0; i < mLocationListeners.length; i++) {
54            Location l = mLocationListeners[i].current();
55            if (l != null) {
56                return l;
57            }
58        }
59        Log.d(TAG, "No location received yet.");
60        return null;
61    }
62
63    @Override
64    public void recordLocation(boolean recordLocation) {
65        if (mRecordLocation != recordLocation) {
66            mRecordLocation = recordLocation;
67            if (recordLocation) {
68                startReceivingLocationUpdates();
69            } else {
70                stopReceivingLocationUpdates();
71            }
72        }
73    }
74
75    @Override
76    public void disconnect() {
77        Log.d(TAG, "disconnect");
78        // The onPause() call to stopReceivingLocationUpdates is sufficient to unregister the
79        // Network/GPS listener.
80    }
81
82    private void startReceivingLocationUpdates() {
83        Log.v(TAG, "starting location updates");
84        if (mLocationManager == null) {
85            mLocationManager = AndroidServices.instance().provideLocationManager();
86        }
87        if (mLocationManager != null) {
88            try {
89                mLocationManager.requestLocationUpdates(
90                        android.location.LocationManager.NETWORK_PROVIDER,
91                        1000,
92                        0F,
93                        mLocationListeners[1]);
94            } catch (SecurityException ex) {
95                Log.i(TAG, "fail to request location update, ignore", ex);
96            } catch (IllegalArgumentException ex) {
97                Log.d(TAG, "provider does not exist " + ex.getMessage());
98            }
99            try {
100                mLocationManager.requestLocationUpdates(
101                        android.location.LocationManager.GPS_PROVIDER,
102                        1000,
103                        0F,
104                        mLocationListeners[0]);
105            } catch (SecurityException ex) {
106                Log.i(TAG, "fail to request location update, ignore", ex);
107            } catch (IllegalArgumentException ex) {
108                Log.d(TAG, "provider does not exist " + ex.getMessage());
109            }
110            Log.d(TAG, "startReceivingLocationUpdates");
111        }
112    }
113
114    private void stopReceivingLocationUpdates() {
115        Log.v(TAG, "stopping location updates");
116        if (mLocationManager != null) {
117            for (int i = 0; i < mLocationListeners.length; i++) {
118                try {
119                    mLocationManager.removeUpdates(mLocationListeners[i]);
120                } catch (Exception ex) {
121                    Log.i(TAG, "fail to remove location listners, ignore", ex);
122                }
123            }
124            Log.d(TAG, "stopReceivingLocationUpdates");
125        }
126    }
127
128    private class LocationListener
129            implements android.location.LocationListener {
130        Location mLastLocation;
131        boolean mValid = false;
132        String mProvider;
133
134        public LocationListener(String provider) {
135            mProvider = provider;
136            mLastLocation = new Location(mProvider);
137        }
138
139        @Override
140        public void onLocationChanged(Location newLocation) {
141            if (newLocation.getLatitude() == 0.0
142                    && newLocation.getLongitude() == 0.0) {
143                // Hack to filter out 0.0,0.0 locations
144                return;
145            }
146            if (!mValid) {
147                Log.d(TAG, "Got first location.");
148            }
149            mLastLocation.set(newLocation);
150            mValid = true;
151        }
152
153        @Override
154        public void onProviderEnabled(String provider) {
155        }
156
157        @Override
158        public void onProviderDisabled(String provider) {
159            mValid = false;
160        }
161
162        @Override
163        public void onStatusChanged(
164                String provider, int status, Bundle extras) {
165            switch(status) {
166                case android.location.LocationProvider.OUT_OF_SERVICE:
167                case android.location.LocationProvider.TEMPORARILY_UNAVAILABLE: {
168                    mValid = false;
169                    break;
170                }
171            }
172        }
173
174        public Location current() {
175            return mValid ? mLastLocation : null;
176        }
177    }
178}
179