1 package org.opencpn;
2 
3 import android.app.AlertDialog;
4 import android.app.Service;
5 import android.content.Context;
6 import android.content.DialogInterface;
7 import android.content.Intent;
8 import android.content.pm.PackageManager;
9 import android.location.Location;
10 import android.location.LocationListener;
11 import android.location.LocationManager;
12 import android.location.GpsStatus;
13 import android.location.GpsSatellite;
14 
15 import android.os.Bundle;
16 import android.os.IBinder;
17 import android.os.HandlerThread;
18 import android.os.SystemClock;
19 import android.provider.Settings;
20 import android.util.Log;
21 import android.app.Activity;
22 import android.os.Handler;
23 import java.util.List;
24 import java.lang.Math;
25 import java.lang.Iterable;
26 import java.util.Iterator;
27 
28 import org.opencpn.OCPNGpsNmeaListener;
29 import org.opencpn.OCPNNativeLib;
30 import org.qtproject.qt5.android.bindings.QtActivity;
31 
32 
33 
34 public class GPSServer extends Service implements LocationListener {
35 
36     private final static int GPS_OFF = 0;
37     private final static int GPS_ON = 1;
38     public  final static int GPS_PROVIDER_AVAILABLE = 2;
39     private final static int GPS_SHOWPREFERENCES = 3;
40 
41     private final Context mContext;
42     private final Activity parent_activity;
43 
44     public String status_string;
45 
46     boolean isThreadStarted = false;
47     HandlerThread mLocationHandlerThread;
48 
49     OCPNGpsNmeaListener mNMEAListener;
50     OCPNNativeLib mNativeLib;
51 
52     // flag for GPS status
53     boolean isGPSEnabled = false;
54 
55     // flag for network status
56     boolean isNetworkEnabled = false;
57 
58     // flag for GPS status
59     boolean canGetLocation = false;
60 
61     Location mLastLocation; // location
62     double latitude; // latitude
63     double longitude; // longitude
64     float course;
65     float speed;
66 
67     private GpsStatus mStatus;
68     private MyListener mMyListener;
69     long mLastLocationMillis;
70     boolean isGPSFix = false;
71     public int m_watchDog = 0;
72 
73     int m_tick;
74 
75     // The minimum distance to change Updates in meters
76     private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 1; // 1 meter
77 
78     // The minimum time between updates in milliseconds
79     private static final long MIN_TIME_BW_UPDATES = 1000; // 1 second
80 
81     // Declaring a Location Manager
82     protected LocationManager locationManager;
83 
84     private class MyListener implements GpsStatus.Listener {
85         @Override
onGpsStatusChanged(int event)86         public void onGpsStatusChanged(int event) {
87 //            Log.i("DEBUGGER_TAG", "StatusListener Event");
88 
89             if(null != locationManager){
90                 mStatus = locationManager.getGpsStatus(mStatus);
91             }
92 
93 
94             switch (event) {
95                 case GpsStatus.GPS_EVENT_STARTED:
96                     Log.i("DEBUGGER_TAG", "GPS_EVENT_STARTED Event");
97                     break;
98 
99                 case GpsStatus.GPS_EVENT_STOPPED:
100                     Log.i("DEBUGGER_TAG", "GPS_EVENT_STOPPED Event");
101                     isGPSFix = false;
102                     break;
103 
104                 case GpsStatus.GPS_EVENT_FIRST_FIX:
105                     Log.i("DEBUGGER_TAG", "GPS_EVENT_FIRST_FIX Event");
106                     isGPSFix = true;
107                     break;
108 
109                 case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
110 //                    Log.i("DEBUGGER_TAG", "GPS_EVENT_SATELLITE_STATUS Event");
111 
112                         int nSatsUsed = 0;
113                          // int maxSatellites = gpsStatus.getMaxSatellites();    // appears fixed at 255
114                          Iterable<GpsSatellite>satellites = mStatus.getSatellites();
115                          Iterator<GpsSatellite>satI = satellites.iterator();
116                          while (satI.hasNext()) {
117                              GpsSatellite satellite = satI.next();
118 //                             Log.i("DEBUGGER_TAG", "onGpsStatusChanged(): " + satellite.getPrn() + "," + satellite.usedInFix() + "," + satellite.getSnr() + "," + satellite.getAzimuth() + "," + satellite.getElevation());
119                              if(satellite.usedInFix())
120                              nSatsUsed++;
121                          }
122 
123                     if(nSatsUsed < 3)
124                         isGPSFix = false;
125 
126                     break;
127             }
128         }
129     }
130 
GPSServer(Context context, OCPNNativeLib nativelib, Activity activity)131     public GPSServer(Context context, OCPNNativeLib nativelib, Activity activity) {
132         this.mContext = context;
133         this.mNativeLib = nativelib;
134         this.parent_activity = activity;
135 //        getLocation();
136     }
137 
doService( int parm )138     public String doService( int parm )
139     {
140         String ret_string = "???";
141         locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
142 
143         switch (parm){
144             case GPS_OFF:
145             Log.i("DEBUGGER_TAG", "GPS OFF");
146 
147             if(locationManager != null){
148                 if(isThreadStarted){
149                     locationManager.removeUpdates(GPSServer.this);
150                     locationManager.removeNmeaListener (mNMEAListener);
151                     isThreadStarted = false;
152                 }
153             }
154 
155             ret_string = "GPS_OFF OK";
156             break;
157 
158             case GPS_ON:
159                 Log.i("DEBUGGER_TAG", "GPS ON");
160 
161                 isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
162 
163                 if(isGPSEnabled){
164                     Log.i("DEBUGGER_TAG", "GPS is Enabled");
165                 }
166                 else{
167                     Log.i("DEBUGGER_TAG", "GPS is <<<<DISABLED>>>>");
168                     ret_string = "GPS is disabled";
169                     status_string = ret_string;
170                     return ret_string;
171                 }
172 
173 /*
174                 isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
175                 if(isNetworkEnabled)
176                     Log.i("DEBUGGER_TAG", "Network is Enabled");
177                 else
178                     Log.i("DEBUGGER_TAG", "Network is <<<<DISABLED>>>>");
179 */
180 
181                 if(!isThreadStarted){
182 
183                     parent_activity.runOnUiThread(new Runnable()   {
184                         LocationManager locationManager;
185                         public void run()   {
186 
187                             locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
188                             Log.i("DEBUGGER_TAG", "Requesting Updates");
189                             locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,1000,1, GPSServer.this);
190 
191                             mNMEAListener = new OCPNGpsNmeaListener(mNativeLib, GPSServer.this);
192                             locationManager.addNmeaListener (mNMEAListener);
193 
194                             mMyListener = new MyListener();
195                             locationManager.addGpsStatusListener(mMyListener);
196 
197                         }
198                     });
199 
200 
201                     HandlerThread hThread = new HandlerThread("HandlerThread");
202                     hThread.start();
203                     final Handler handler = new Handler(hThread.getLooper());
204 
205 
206                     Runnable ticker = new Runnable() {
207                         @Override
208                         public void run() {
209 //                            Log.i("DEBUGGER_TAG", "Tick");
210 
211                             m_tick++;
212                             m_watchDog++;
213 
214                             if(isGPSEnabled && (m_watchDog > 10)){
215                                 if(null != locationManager){
216                                     mLastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
217                                     if (mLastLocation != null) {
218                                         latitude = mLastLocation.getLatitude();
219                                         longitude = mLastLocation.getLongitude();
220                                         course = mLastLocation.getBearing();
221                                         speed = mLastLocation.getSpeed();
222                                     }
223 
224                                     if(null != mNativeLib){
225                                         String s = createRMC();
226                                         mNativeLib.processNMEA( s );
227                                     }
228                                 }
229                             }
230 
231                             handler.postDelayed(this, 1000);
232                             }
233                         };
234 
235                     // Schedule the first execution
236                     handler.postDelayed(ticker, 1000);
237 
238 
239                     isThreadStarted = true;
240                 }
241 
242                 ret_string = "GPS_ON OK";
243                 break;
244 
245             case GPS_PROVIDER_AVAILABLE:
246             if(hasGPSDevice( mContext )){
247                     ret_string = "YES";
248                     Log.i("DEBUGGER_TAG", "Provider yes");
249                 }
250                 else{
251                     ret_string = "NO";
252                     Log.i("DEBUGGER_TAG", "Provider no");
253                 }
254 
255                 break;
256 
257             case GPS_SHOWPREFERENCES:
258                 showSettingsAlert();
259                 break;
260 
261         }   // switch
262 
263 
264         status_string = ret_string;
265         return ret_string;
266      }
267 
268 
269 
hasGPSDevice(Context context)270      public boolean hasGPSDevice(Context context)
271      {
272 
273  //        This code crashes unless run from the GUI thread, so is moved to the QtActivity initialization
274  //        PackageManager packMan = getPackageManager();
275  //        return packMan.hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);
276 
277     // This code produces false positive for some generic android tablets.
278          final LocationManager mgr = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
279          if ( mgr == null )
280             return false;
281          final List<String> providers = mgr.getAllProviders();
282          if ( providers == null )
283             return false;
284          return providers.contains(LocationManager.GPS_PROVIDER);
285 
286      }
287 
288 
getLocation()289     public Location getLocation() {
290         try {
291             locationManager = (LocationManager) mContext
292                     .getSystemService(LOCATION_SERVICE);
293 
294             // getting GPS status
295             isGPSEnabled = locationManager
296                     .isProviderEnabled(LocationManager.GPS_PROVIDER);
297 
298             // getting network status
299             isNetworkEnabled = locationManager
300                     .isProviderEnabled(LocationManager.NETWORK_PROVIDER);
301 
302             if (!isGPSEnabled && !isNetworkEnabled) {
303                 // no network provider is enabled
304             } else {
305                 this.canGetLocation = true;
306                 // First get location from Network Provider
307                 if (isNetworkEnabled) {
308                     locationManager.requestLocationUpdates(
309                             LocationManager.NETWORK_PROVIDER,
310                             MIN_TIME_BW_UPDATES,
311                             MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
312                     Log.d("Network", "Network");
313                     if (locationManager != null) {
314                         mLastLocation = locationManager
315                                 .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
316                         if (mLastLocation != null) {
317                             latitude = mLastLocation.getLatitude();
318                             longitude = mLastLocation.getLongitude();
319                         }
320                     }
321                 }
322                 // if GPS Enabled get lat/long using GPS Services
323                 if (isGPSEnabled) {
324                     if (mLastLocation == null) {
325                         locationManager.requestLocationUpdates(
326                                 LocationManager.GPS_PROVIDER,
327                                 MIN_TIME_BW_UPDATES,
328                                 MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
329                         Log.d("GPS Enabled", "GPS Enabled");
330                         if (locationManager != null) {
331                             mLastLocation = locationManager
332                                     .getLastKnownLocation(LocationManager.GPS_PROVIDER);
333                             if (mLastLocation != null) {
334                                 latitude = mLastLocation.getLatitude();
335                                 longitude = mLastLocation.getLongitude();
336                             }
337                         }
338                     }
339                 }
340             }
341 
342         } catch (Exception e) {
343             e.printStackTrace();
344         }
345 
346         return mLastLocation;
347     }
348 
349     /**
350      * Stop using GPS listener
351      * Calling this function will stop using GPS in your app
352      * */
stopUsingGPS()353     public void stopUsingGPS(){
354         if(locationManager != null){
355             locationManager.removeUpdates(GPSServer.this);
356         }
357     }
358 
359     /**
360      * Function to get latitude
361      * */
getLatitude()362     public double getLatitude(){
363         if(mLastLocation != null){
364             latitude = mLastLocation.getLatitude();
365         }
366 
367         // return latitude
368         return latitude;
369     }
370 
371     /**
372      * Function to get longitude
373      * */
getLongitude()374     public double getLongitude(){
375         if(mLastLocation != null){
376             longitude = mLastLocation.getLongitude();
377         }
378 
379         // return longitude
380         return longitude;
381     }
382 
383     /**
384      * Function to check GPS/wifi enabled
385      * @return boolean
386      * */
canGetLocation()387     public boolean canGetLocation() {
388         return this.canGetLocation;
389     }
390 
391     /**
392      * Function to show settings alert dialog
393      * On pressing Settings button will lauch Settings Options
394      * */
showSettingsAlert()395     public void showSettingsAlert(){
396         AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
397 
398         // Setting Dialog Title
399         alertDialog.setTitle("GPS is settings");
400 
401         // Setting Dialog Message
402         alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
403 
404         // On pressing Settings button
405         alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
406             public void onClick(DialogInterface dialog,int which) {
407                 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
408                 mContext.startActivity(intent);
409             }
410         });
411 
412         // on pressing cancel button
413         alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
414             public void onClick(DialogInterface dialog, int which) {
415             dialog.cancel();
416             }
417         });
418 
419         // Showing Alert Message
420         alertDialog.show();
421     }
422 
423     @Override
onLocationChanged(Location location)424     public void onLocationChanged(Location location) {
425         Log.i("DEBUGGER_TAG", "onLocationChanged");
426         if (location == null) return;
427 
428         mLastLocationMillis = SystemClock.elapsedRealtime();
429 
430         mLastLocation = location;
431     }
432 
433     @Override
onProviderDisabled(String provider)434     public void onProviderDisabled(String provider) {
435         Log.i("DEBUGGER_TAG", "onProviderDisabled " + provider);
436 
437     }
438 
439     @Override
onProviderEnabled(String provider)440     public void onProviderEnabled(String provider) {
441         Log.i("DEBUGGER_TAG", "onProviderEnabled " + provider);
442 
443     }
444 
445     @Override
onStatusChanged(String provider, int status, Bundle extras)446     public void onStatusChanged(String provider, int status, Bundle extras) {
447         Log.i("DEBUGGER_TAG", "onStatusChanged");
448 
449     }
450 
451 
452     @Override
onBind(Intent arg0)453     public IBinder onBind(Intent arg0) {
454         return null;
455     }
456 
createRMC()457     private String createRMC(){
458         // Create an NMEA sentence
459         String s = "$LCRMC,,";
460         if(isGPSFix)
461             s = s.concat("A,");
462         else
463             s = s.concat("V,");
464 
465 
466         String slat = "";
467         double ltt = latitude;
468         if(latitude < 0)
469             ltt = -latitude;
470 
471         double d0 = Math.floor(ltt);
472         double d1 = ltt-d0;
473         double d2 = Math.floor(d1 * 60);
474         double d3 = (d1*60.) - d2;
475 
476         slat = slat.format("%.0f.%.0f,", (d0 * 100.) + d2, d3 * 10000);
477 
478         if(latitude > 0)
479             slat = slat.concat("N,");
480         else
481             slat = slat.concat("S,");
482 
483 
484         s = s.concat(slat);
485 
486         String slon = "";
487         double lot = longitude;
488         if(longitude < 0)
489             lot = -longitude;
490 
491         d0 = Math.floor(lot);
492         d1 = lot-d0;
493         d2 = Math.floor(d1 * 60);
494         d3 = (d1*60.) - d2;
495 
496         if(d0 < 100.)
497             slon = "0";
498         slon = slon.concat(slon.format("%.0f.%.0f,", (d0 * 100.) + d2, d3 * 10000));
499 
500         if(longitude > 0)
501             slon = slon.concat("E,");
502         else
503             slon = slon.concat("W,");
504 
505         s = s.concat(slon);
506 
507         String sspeed = "";
508         sspeed = sspeed.format("%.2f,", speed /.5144);
509         s = s.concat(sspeed);
510 
511         String strack = "";
512         strack = strack.format("%.0f,", course);
513         s = s.concat(strack);
514 
515         s = s.concat(",,,");      // unused fields
516 
517         s = s.concat("*55");    // checksum
518 
519 //        s = s.concat("\r\n");
520 
521         Log.i("DEBUGGER_TAG", s);
522 
523         return s;
524     }
525 }
526 
527 
528 
529 //GPSTracker gps = new GPSTracker(this);
530 //if(gps.canGetLocation()){ // gps enabled} // return boolean true/false
531 
532 //Getting Latitude and Longitude
533 //gps.getLatitude(); // returns latitude
534 //gps.getLongitude(); // returns longitude
535 
536 //Showing GPS Settings Alert Dialog
537 //gps.showSettingsAlert();
538 
539 //Stop using GPS
540 //gps.stopUsingGPS();
541