|
2 | 2 |
|
3 | 3 | import android.content.Context; |
4 | 4 | import android.content.Intent; |
| 5 | +import android.content.SharedPreferences; |
| 6 | +import android.content.pm.PackageManager; |
5 | 7 | import android.location.Location; |
| 8 | +import android.location.LocationListener; |
6 | 9 | import android.location.LocationManager; |
| 10 | +import android.location.LocationProvider; |
| 11 | +import android.net.wifi.SupplicantState; |
| 12 | +import android.net.wifi.WifiInfo; |
| 13 | +import android.net.wifi.WifiManager; |
| 14 | +import android.os.Build; |
| 15 | +import android.os.Bundle; |
| 16 | +import android.os.Looper; |
| 17 | +import android.preference.PreferenceManager; |
| 18 | +import android.support.v4.content.ContextCompat; |
7 | 19 | import android.util.Log; |
8 | 20 |
|
9 | 21 | /** |
10 | 22 | * Created by fritz on 14/01/17. |
11 | 23 | */ |
12 | 24 |
|
13 | | -public class ButlerLocation { |
| 25 | +public class ButlerLocation implements LocationListener { |
14 | 26 | private String LOG_TAG = "BUTLER > Location"; |
15 | 27 | Context context; |
16 | 28 | private Object obj; |
17 | 29 | private boolean runLocationThread = false; |
18 | 30 | private boolean running = false; |
| 31 | + private Long lastGpsLocation = null; |
| 32 | + private int locationInterval; |
| 33 | + private LocationManager lm = null; |
| 34 | + private SharedPreferences settings; |
| 35 | + |
19 | 36 |
|
20 | 37 | public void init(Context context) { |
21 | 38 | this.context = context; |
22 | 39 | Log.i(LOG_TAG, "ButlerLocation > init"); |
23 | 40 | obj = new Object(); // for Location loop |
24 | | - } |
25 | 41 |
|
26 | | - public void activate() { |
27 | | - this.runLocationThread = true; |
| 42 | + |
| 43 | + lastGpsLocation = System.currentTimeMillis()/1000; |
| 44 | + |
| 45 | + if ( Build.VERSION.SDK_INT >= 23 && |
| 46 | + ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && |
| 47 | + ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { |
| 48 | + return ; |
| 49 | + } |
| 50 | + lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); |
| 51 | + |
| 52 | + |
| 53 | + settings = PreferenceManager.getDefaultSharedPreferences(this.context); |
| 54 | + String strLocationInterval = settings.getString("location_interval", "300"); // 5 minutes per default |
| 55 | + locationInterval = Integer.parseInt(strLocationInterval); |
| 56 | + |
| 57 | + int timeInMs = 1000 * locationInterval; |
| 58 | + int distanceInMeters = 0; |
| 59 | + //lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, timeInMs, distanceInMeters, this); |
| 60 | + Log.d(LOG_TAG, "Checking which locations are enabled..."); |
| 61 | + if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) { |
| 62 | + Log.d(LOG_TAG, "Location by GPS enabled!"); |
| 63 | + lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, timeInMs, distanceInMeters, this); |
| 64 | + } |
| 65 | + // this one must be enabled. Else the onStatusChanged can't be called when the location is enabled on the device |
| 66 | + Log.d(LOG_TAG, "Location by network enabled (no choice ;) )!"); |
| 67 | + lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, timeInMs, distanceInMeters, this); |
28 | 68 | } |
29 | 69 |
|
30 | | - public void deactivate() { |
31 | | - this.runLocationThread = false; |
32 | | - running = false; |
33 | | - // TODO : find a proper way to stop the thread findLocation from here ! |
34 | | - // TODO : find a proper way to stop the thread findLocation from here ! |
35 | | - // TODO : find a proper way to stop the thread findLocation from here ! |
36 | | - // TODO : find a proper way to stop the thread findLocation from here ! |
37 | | -// try { |
38 | | - obj.notify(); |
39 | | -/* |
| 70 | + public void stop() { |
| 71 | + Log.d(LOG_TAG, "Stopping location tracking..."); |
| 72 | + try |
| 73 | + { |
| 74 | + if ( Build.VERSION.SDK_INT >= 23 && |
| 75 | + ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_FINE_LOCATION ) != PackageManager.PERMISSION_GRANTED && |
| 76 | + ContextCompat.checkSelfPermission( context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { |
| 77 | + return ; |
| 78 | + } |
| 79 | + lm.removeUpdates(this); |
| 80 | + lm = null; |
40 | 81 | } |
41 | | - catch (InterruptedException e){ |
42 | | - Log.e(LOG_TAG, "Error while stopping the location thread"); |
| 82 | + catch(Exception e) |
| 83 | + { |
43 | 84 | e.printStackTrace(); |
44 | 85 | } |
45 | | - */ |
46 | | - |
47 | 86 | } |
48 | 87 |
|
49 | | - public void findLocation(int interval) { |
50 | | - /* interval : in seconds */ |
51 | | - if (running == true) { |
52 | | - Log.i(LOG_TAG, "A location thread is already running. Not starting a new one!"); |
53 | | - // TODO :can we do something here to stop the already existing one ? |
54 | | - //return; |
| 88 | + public void onStatusChanged(String provider, int status, Bundle extras) { |
| 89 | + String newStatus = ""; |
| 90 | + switch (status) { |
| 91 | + case LocationProvider.OUT_OF_SERVICE: |
| 92 | + newStatus = "OUT_OF_SERVICE"; |
| 93 | + break; |
| 94 | + case LocationProvider.TEMPORARILY_UNAVAILABLE: |
| 95 | + newStatus = "TEMPORARILY_UNAVAILABLE"; |
| 96 | + break; |
| 97 | + case LocationProvider.AVAILABLE: |
| 98 | + newStatus = "AVAILABLE"; |
| 99 | + break; |
| 100 | + } |
| 101 | + Log.d(LOG_TAG, "onStatusChanged. New status=" + newStatus); |
| 102 | + } |
| 103 | + public void onProviderEnabled(String provider) {} |
| 104 | + public void onProviderDisabled(String provider) {} |
| 105 | + |
| 106 | + public void onLocationChanged(Location location) { |
| 107 | + // Called when a new location is found by the network location provider. |
| 108 | + Log.i(LOG_TAG,"Location changed, " + location.getAccuracy() + " , " + location.getLatitude()+ "," + location.getLongitude() + " from " + location.getProvider()); |
| 109 | + // TODO : how to use only the best value ? as this is called for both GPS and NETWORK |
| 110 | + |
| 111 | + |
| 112 | + WifiManager wifiManager = (WifiManager) this.context.getSystemService(Context.WIFI_SERVICE); |
| 113 | + WifiInfo wifiInfo; |
| 114 | + |
| 115 | + String locationName = ""; |
| 116 | + wifiInfo = wifiManager.getConnectionInfo(); |
| 117 | + if (wifiInfo.getSupplicantState() == SupplicantState.COMPLETED) { |
| 118 | + String ssid = wifiInfo.getSSID(); |
| 119 | + ssid = ssid.replace("\"", ""); |
| 120 | + Log.i(LOG_TAG, "Location over wifi. SSID = " + ssid); |
| 121 | + // TODO : do the loop |
| 122 | + String aSsid = settings.getString("location_wifi_1_ssid", ""); |
| 123 | + Log.d(LOG_TAG, "Comparing '" + ssid + "' to '" + aSsid + "'"); |
| 124 | + if (aSsid.equals(ssid)) { |
| 125 | + String foundLocation = settings.getString("location_wifi_1_name", ""); |
| 126 | + Log.i(LOG_TAG, "The SSID '" + ssid + "' is related to the location : " + foundLocation); |
| 127 | + locationName = foundLocation; |
| 128 | + } |
55 | 129 |
|
56 | 130 | } |
57 | | - try { |
58 | | - running = true; |
59 | | - boolean gps_enabled = false; |
60 | | - boolean network_enabled = false; |
61 | | - |
62 | | - LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); |
63 | | - |
64 | | - synchronized (obj) { |
65 | | - while (runLocationThread) { |
66 | | - try { |
67 | | - gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER); |
68 | | - network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); |
69 | | - |
70 | | - Location net_loc = null, gps_loc = null, finalLoc = null; |
71 | | - |
72 | | - if (gps_enabled) |
73 | | - gps_loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER); |
74 | | - if (network_enabled) |
75 | | - net_loc = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); |
76 | | - |
77 | | - if (gps_loc != null && net_loc != null) { |
78 | | - |
79 | | - //smaller the number more accurate result will |
80 | | - if (gps_loc.getAccuracy() > net_loc.getAccuracy()) |
81 | | - finalLoc = net_loc; |
82 | | - else |
83 | | - finalLoc = gps_loc; |
84 | | - |
85 | | - // I used this just to get an idea (if both avail, its upto you which you want to take as I've taken location with more accuracy) |
86 | | - |
87 | | - } else { |
88 | | - |
89 | | - if (gps_loc != null) { |
90 | | - finalLoc = gps_loc; |
91 | | - } else if (net_loc != null) { |
92 | | - finalLoc = net_loc; |
93 | | - } |
94 | | - } |
95 | | - |
96 | | - if (finalLoc != null) { |
97 | | - // This one will be catched by the ButlerService |
98 | | - Intent i = new Intent("org.domogik.butler.Location"); |
99 | | - i.putExtra("latitude", finalLoc.getLatitude()); |
100 | | - i.putExtra("longitude", finalLoc.getLongitude()); |
101 | | - context.sendBroadcast(i); |
102 | | - |
103 | | - Log.i(LOG_TAG, "Location is : " + finalLoc); |
104 | | - //latitude = location.getLatitude(); |
105 | | - //longitude = location.getLongitude(); |
106 | | - } |
107 | | - } catch (Exception e) { |
108 | | - Log.e(LOG_TAG, "Error while getting the location"); |
109 | | - e.printStackTrace(); |
110 | | - } |
111 | | - obj.wait(interval * 1000); // 3 000 000 = 5 minutes |
112 | | - } |
| 131 | + |
| 132 | + |
| 133 | + |
| 134 | + Long now = System.currentTimeMillis()/1000; |
| 135 | + // if the last time we see a GPS signal is bigger than twice the interval, we use the network value |
| 136 | + if (location.getProvider().equals("network")) { |
| 137 | + Log.d(LOG_TAG, "No GPS location, using the network one"); |
| 138 | + if (now - lastGpsLocation > locationInterval * 2) { // TODO : try with 1.5 ? |
| 139 | + Intent i = new Intent("org.domogik.butler.Location"); |
| 140 | + i.putExtra("locationName", locationName); |
| 141 | + i.putExtra("latitude", location.getLatitude()); |
| 142 | + i.putExtra("longitude", location.getLongitude()); |
| 143 | + context.sendBroadcast(i); |
| 144 | + Log.i(LOG_TAG, "Location is sent!"); |
| 145 | + |
113 | 146 | } |
114 | | - } catch (Exception e) { |
115 | | - running = false; |
116 | | - Log.e(LOG_TAG, "Error while setting the location"); |
117 | | - e.printStackTrace(); |
118 | | - Log.i(LOG_TAG, "End of the thread (because of the previous error)!"); |
119 | | - running = false; |
| 147 | + else { |
| 148 | + Log.i(LOG_TAG, "Network value only and " + (now - lastGpsLocation) + " < " + (locationInterval * 2) + ""); |
| 149 | + } |
| 150 | + // else... yes,.. we could lose a value... maybe to improve ? (TODO) |
| 151 | + } |
| 152 | + else { |
| 153 | + Intent i = new Intent("org.domogik.butler.Location"); |
| 154 | + i.putExtra("locationName", locationName); |
| 155 | + i.putExtra("latitude", location.getLatitude()); |
| 156 | + i.putExtra("longitude", location.getLongitude()); |
| 157 | + context.sendBroadcast(i); |
| 158 | + Log.i(LOG_TAG, "Location is sent!"); |
| 159 | + |
120 | 160 | } |
121 | | - Log.i(LOG_TAG, "End of the thread!"); |
122 | | - running = false; |
| 161 | + lastGpsLocation = now; |
| 162 | + |
123 | 163 | } |
| 164 | + |
124 | 165 | } |
0 commit comments