NMEA解析添加北斗支持
authorsnickersun <scy@incartech.cn>
Thu, 24 Dec 2020 08:01:35 +0000 (16:01 +0800)
committersnickersun <scy@incartech.cn>
Thu, 24 Dec 2020 08:01:35 +0000 (16:01 +0800)
app/src/main/java/com/enqualcomm/support/NMEAListener.java

index 0323497..97add69 100644 (file)
-package com.enqualcomm.support;\r
-\r
-import android.content.Context;\r
-import android.location.Criteria;\r
-import android.location.GpsSatellite;\r
-import android.location.GpsStatus;\r
-import android.location.GpsStatus.NmeaListener;\r
-\r
-import android.location.Location;\r
-import android.location.LocationListener;\r
-import android.location.LocationManager;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.os.Message;\r
-import android.provider.Settings;\r
-\r
-import com.enqualcomm.support.bean.ICLocation;\r
-import com.enqualcomm.support.bean.Runtime;\r
-import com.enqualcomm.support.utils.FileOutputUtil;\r
-import com.enqualcomm.support.utils.ICLogger;\r
-import com.enqualcomm.support.utils.TimeUtil;\r
-import com.enqualcomm.support.bean.ICLocation.GPS_locationStatus;\r
-import java.text.DecimalFormat;\r
-import java.util.ArrayList;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-\r
-import rx.Single;\r
-import rx.android.schedulers.AndroidSchedulers;\r
-import rx.functions.Action1;\r
-\r
-import static android.location.LocationManager.GPS_PROVIDER;\r
-\r
-public class NMEAListener implements NmeaListener, LocationListener {\r
-  private static boolean listening = false;\r
-\r
-  public boolean isListening() {\r
-    return listening;\r
-  }\r
-\r
-  private LocationManager locationManager;\r
-  private String locationInfo;\r
-\r
-  private double longitude;\r
-  private double latitude;\r
-\r
-  private boolean noStop = false;\r
-\r
-\r
-  private int SearchTimeout = 120;\r
-  private int noSignalCount = 0;\r
-  private int searchCout = 0;\r
-  private GPS_CURRENT_STATUS gpsMode;\r
-  int numberOfSatellites;\r
-  Runtime runtime;\r
-\r
-  private static int MaxFixedTimes = 3;\r
-\r
-  private static int locationFixedCount = 0;\r
-\r
-\r
-  private static location_callback mCallback = null;\r
-\r
-  public interface location_callback {\r
-    public void on_locating_changed(GPS_locationStatus gps_status);\r
-  }\r
-\r
-  public static void set_callback(location_callback callback) {\r
-    mCallback = callback;\r
-  }\r
-\r
-  private GPS_locationStatus gps_status = new GPS_locationStatus();\r
-\r
-  public GPS_locationStatus get_gps_status() {\r
-    return gps_status;\r
-  }\r
-\r
-\r
-  public void setNoStop(boolean nostop) {\r
-    if (Config.noLocationCycle==false)\r
-      noStop = nostop;\r
-    else\r
-        ICLogger.i("skip setNoStop " + nostop);\r
-    ICLogger.i("setNoStop " + nostop);\r
-    if (noStop == false) {\r
-      switch (runtime.getLocationInstance().getWorkingMod()) {\r
-        case ICLocation.CUSTOM_MOD:\r
-        case ICLocation.CUSTOM_MOD8_GPS:\r
-        case ICLocation.EMERGNECY_MOD:\r
-        case ICLocation.REALTIME_MOD:\r
-          //GPS 定位模式不关闭GPS,防止 1分钟定位超时后,重新关闭开启GPS。\r
-          //不给GPS继续定位的机会,造成第一次定位困难!\r
-          break;\r
-        case ICLocation.LOWPOWER_MOD:\r
-        case ICLocation.NORMAL_MOD:\r
-        case ICLocation.CUSTOM_MOD8_WIFI:\r
-        default:\r
-          ICLogger.i("非GPS定位模式,关闭GPS");\r
-          //非GPS定位模式的话,需要关闭GPS。\r
-          stopListen();\r
-          break;\r
-      }\r
-\r
-    }\r
-  }\r
-\r
-  public NMEAListener(LocationManager paramLocationManager, Runtime paramRuntime) {\r
-    this.locationManager = paramLocationManager;\r
-    this.runtime = paramRuntime;\r
-  }\r
-\r
-  static int satindex = 0;\r
-\r
-  public void onNmeaReceived(long paramLong, String nmeastr) {\r
-//    EqcAlgorithmNative.native_EqcAlgorithmMethod5(paramString);\r
-//    ICLogger.i("Nmea :"+nmeastr+" "+paramLong);\r
-\r
-    if (Config.LOG_TOFILE)\r
-      ICLogger.logToFile("Nmea", nmeastr);\r
-\r
-    if (nmeastr.startsWith("$RD_RSSI")) {\r
-        //每组NMEA数据的头,只适用于 SL8521E,9820E\r
-        gps_status.numSatelliteList.clear();\r
-       gps_status.search_time_cost = searchCout;\r
-    }\r
-\r
-    if (nmeastr.startsWith("$GPVTG")) {\r
-      //每组NMEA数据的尾,只适用于 SL8521E,9820E\r
-      searchCout++;\r
-      //最后一页,打印搜星情况,并作一些判断。\r
-      StringBuilder sb = new StringBuilder();\r
-      sb.append("搜索" + searchCout + "次,搜索到卫星个数" + gps_status.satlite_numbss + ", [SNR>0] =" + runtime.getLocationInstance().numSatelliteList.size());\r
-      sb.append(", Max 5 SNR [");\r
-      for (int i = 0; i < runtime.getLocationInstance().max3Satellite.size(); i++) {\r
-        sb.append(runtime.getLocationInstance().max3Satellite.get(i).getSnr() + ",");\r
-      }\r
-      sb.append("]");\r
-      if (Config.LOG_TOFILE)\r
-        ICLogger.logToFile( "GPS", sb.toString());\r
-\r
-      ICLogger.i(sb.toString());\r
-      // 卫星总数小于2 ,或者 snr小于20\r
-      if (runtime.getLocationInstance().numSatelliteList.size() < 3 && (runtime.getLocationInstance().max3Satellite.size() > 0 ? (runtime.getLocationInstance().max3Satellite.get(0).getSnr() < 20 ? true : false) : true)) {\r
-        noSignalCount++;\r
-      }else{\r
-        noSignalCount=0;//只要有一次满足有信号,则重新开始计数。\r
-      }\r
-\r
-\r
-      StringBuilder sb2 = new StringBuilder();\r
-      if (!noStop) {\r
-        if (searchCout > ICLocation.MAX_GPS_SEARCH_TIMEOUT) {\r
-          sb2.append(" 搜索" + searchCout + "次未定位,超过" + ICLocation.MAX_GPS_SEARCH_TIMEOUT + "限制退出GPS定位");\r
-\r
-          runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_GPS_TIEMOUT);\r
-\r
-          stop(MSG_WHAT_GPS_TIMEOUT);\r
-        }\r
-        if (noSignalCount > ICLocation.MAX_GPS_NOSIGNAL_COUNT) {\r
-          sb2.append(" 搜索" + searchCout + "次,超过" + noSignalCount + "次没有收到星,退出GPS定位");\r
-          runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_GPS_TIEMOUT);\r
-          stop(MSG_WHAT_GPS_NOSTAR);\r
-        }\r
-      }\r
-      ICLogger.i(sb2.toString());\r
-      if (Config.LOG_TOFILE)\r
-        ICLogger.logToFile("GPS", sb2.toString());\r
-\r
-\r
-      if (mCallback != null)\r
-        mCallback.on_locating_changed(get_gps_status());\r
-    }\r
-    if (nmeastr.startsWith("$GPGLL,")) {\r
-      String tmplist[] = nmeastr.split(",");\r
-//      GPGLL编辑\r
-//(地理定位信息)\r
-//      例:$GPGLL,4250.5589,S,14718.5084,E,092204.999,A*2D\r
-//      字段0:$GPGLL,语句ID,表明该语句为Geographic Position(GLL)地理定位信息\r
-//      字段1:纬度ddmm.mmmm,度分格式(前导位数不足则补0)\r
-//      字段2:纬度N(北纬)或S(南纬)\r
-//      字段3:经度dddmm.mmmm,度分格式(前导位数不足则补0)\r
-//      字段4:经度E(东经)或W(西经)\r
-//      字段5:UTC时间,hhmmss.sss格式\r
-//      字段6:状态,A=定位,V=未定位\r
-//      字段7:校验值($与*之间的数异或后的值)\r
-      String Lat = tmplist[1];\r
-      String lon = tmplist[3];\r
-      String fixed = tmplist[6];\r
-//      ICLogger.i("GPGLL Lat="+Lat+",Lon="+lon+",fixed="+fixed);\r
-\r
-    } else if (nmeastr.startsWith("$GPRMC,")) {\r
-//      GPRMC编辑\r
-//(推荐定位信息数据格式)\r
-//      例:$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50\r
-//      字段0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息\r
-//      字段1:UTC时间,hhmmss.sss格式\r
-//      字段2:状态,A=定位,V=未定位\r
-//      字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)\r
-//      字段4:纬度N(北纬)或S(南纬)\r
-//      字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)\r
-//      字段6:经度E(东经)或W(西经)\r
-//      字段7:速度,节,Knots\r
-//      字段8:方位角,度\r
-//      字段9:UTC日期,DDMMYY格式\r
-//      字段10:磁偏角,(000 - 180)度(前导位数不足则补0)\r
-//      字段11:磁偏角方向,E=东W=西\r
-//      字段12:模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)\r
-//      字段13:校验值($与*之间的数异或后的值)\r
-      String tmplist[] = nmeastr.split(",");\r
-      String utctime = tmplist[1];\r
-      String Lat = tmplist[3];\r
-      String lon = tmplist[5];\r
-      String fixed = tmplist[2];\r
-      String speed = tmplist[7];\r
-//      ICLogger.i("GPRMC GPSTime="+utctime+",Lat="+Lat+",Lon="+lon+",fixed="+fixed+",speed="+speed);\r
-//      if (Config.LOG_TOFILE)\r
-//        FileOutputUtil.fileOutput(this.runtime.getCacheDir(), "GPS", "GPRMC GPSTime="+utctime+",Lat="+Lat+",Lon="+lon+",fixed="+fixed+",speed="+speed);\r
-      if (fixed.trim().equals("A")) {\r
-        if (speed.trim().isEmpty()) speed = "0.0";\r
-        runtime.getLocationInstance().setSpeed(Float.valueOf(speed));\r
-      }\r
-\r
-\r
-    } else if (nmeastr.startsWith("$GPGSV,")) {\r
-\r
-//    GPGSV编辑\r
-//            (可见卫星信息)\r
-//    例:$GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,069,,13,32,252,45*70\r
-//    字段0:$GPGSV,语句ID,表明该语句为GPS Satellites in View(GSV)可见卫星信息\r
-//    字段1:本次GSV语句的总数目(1 - 3)\r
-//    字段2:本条GSV语句是本次GSV语句的第几条(1 - 3)\r
-//    字段3:当前可见卫星总数(00 - 12)(前导位数不足则补0)\r
-//    字段4:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)\r
-//    字段5:卫星仰角(00 - 90)度(前导位数不足则补0)\r
-//    字段6:卫星方位角(00 - 359)度(前导位数不足则补0)\r
-//    字段7:信噪比(00-99)dbHz\r
-//    字段8:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)\r
-//    字段9:卫星仰角(00 - 90)度(前导位数不足则补0)\r
-//    字段10:卫星方位角(00 - 359)度(前导位数不足则补0)\r
-//    字段11:信噪比(00-99)dbHz\r
-//    字段12:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)\r
-//    字段13:卫星仰角(00 - 90)度(前导位数不足则补0)\r
-////    字段14:卫星方位角(00 - 359)度(前导位数不足则补0)\r
-////    字段15:信噪比(00-99)dbHz\r
-//    字段16:校验值($与*之间的数异或后的值)\r
-\r
-      String tmplist[] = nmeastr.split(",");\r
-      int maxPageCount = Integer.valueOf(tmplist[1]);\r
-      int currentPage = Integer.valueOf(tmplist[2]);\r
-      int SatlitesCount = Integer.valueOf(tmplist[3]);\r
-      if (maxPageCount > 0 && currentPage == 1) {\r
-        //第一页把数组初始化一遍。\r
-        satindex = 0;\r
-        runtime.getLocationInstance().numSatelliteList.clear(); //清除 SNR >0的卫星\r
-        runtime.getLocationInstance().max3Satellite.clear(); //清除 最大3个星值\r
-\r
-        gps_status.satlite_numbss = SatlitesCount;\r
-      }\r
-      int satcount = (tmplist.length - 4) / 4;\r
-//      ICLogger.i("Nmea :"+nmeastr+" "+satcount);\r
-      runtime.getLocationInstance().set_adding_satlite_flag(true);\r
-      for (int i = 0; i < satcount; i++) {\r
-        satindex++;\r
-        String prn = tmplist[i * 4 + 4];\r
-        String snr = tmplist[i * 4 + 4 + 3];\r
-        if (snr.contains("*")) {\r
-          snr = snr.substring(0, snr.indexOf("*"));\r
-        }\r
-        if (snr.trim().isEmpty()) {\r
-          snr = "0";\r
-        }\r
-//        ICLogger.i("Sat=" + satindex + ",prn=" + prn + ",snr=" + snr);\r
-\r
-        int intprn = Integer.valueOf(prn);\r
-        float floatsnr = Float.valueOf(snr);\r
-        if (floatsnr > 0) {\r
-          //排序取得最大3个SNR\r
-          get3MaxSnrSatellite(new ICLocation.GpsSatellitePriv(intprn, floatsnr));\r
-          runtime.getLocationInstance().numSatelliteList.add(new ICLocation.GpsSatellitePriv(intprn, floatsnr));\r
-          gps_status.numSatelliteList.add(new ICLocation.GpsSatellitePriv(intprn, floatsnr));\r
-        }\r
-      }\r
-\r
-      runtime.getLocationInstance().set_adding_satlite_flag(false);\r
-\r
-    } else if (nmeastr.startsWith("$GPGGA,")) {\r
-\r
-//    GPGGA编辑\r
-//(定位信息)\r
-//    例:$GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,12.2,M,19.7,M,,0000*1F\r
-//    字段0:$GPGGA,语句ID,表明该语句为Global Positioning System Fix Data(GGA)GPS定位信息\r
-//    字段1:UTC 时间,hhmmss.sss,时分秒格式\r
-//    字段2:纬度ddmm.mmmm,度分格式(前导位数不足则补0)\r
-//    字段3:纬度N(北纬)或S(南纬)\r
-//    字段4:经度dddmm.mmmm,度分格式(前导位数不足则补0)\r
-//    字段5:经度E(东经)或W(西经)\r
-//    字段6:GPS状态,0=不可用(FIX NOT valid),1=单点定位(GPS FIX),2=差分定位(DGPS),3=无效PPS,4=实时差分定位(RTK FIX),5=RTK FLOAT,6=正在估算\r
-//    字段7:正在使用的卫星数量(00 - 12)(前导位数不足则补0)\r
-//    字段8:HDOP水平精度因子(0.5 - 99.9)\r
-//    字段9:海拔高度(-9999.9 - 99999.9)\r
-//    字段10:单位:M(米)\r
-//    字段11:地球椭球面相对大地水准面的高度 WGS84水准面划分\r
-//    字段12:WGS84水准面划分单位:M(米)\r
-//    字段13:差分时间(从接收到差分信号开始的秒数,如果不是差分定位将为空)\r
-//    字段14:差分站ID号0000 - 1023(前导位数不足则补0,如果不是差分定位将为空)\r
-//    字段15:校验值($与*之间的数异或后的值)\r
-\r
-      String tmplist[] = nmeastr.split(",");\r
-      String utctime = tmplist[1];\r
-      String Lat = tmplist[2];\r
-      String lon = tmplist[4];\r
-      String latname= tmplist[3];\r
-      String lonname=tmplist[5];\r
-      String fixed = tmplist[6];\r
-      String usedStarts = tmplist[7];\r
-      String hdop = tmplist[8];\r
-\r
-\r
-      if ((fixed.trim().equals("1")) || (fixed.trim().equals("2")) || (fixed.trim().equals("6"))) {\r
-\r
-\r
-        // 转换GPS坐标为度,以便在各种应用中可以方便查找。\r
-        latitude = Double.valueOf(Lat);\r
-        longitude = Double.valueOf(lon);\r
-        // 转换单位,从分转换到度\r
-\r
-        double intdu = (int) (longitude / 100f); //小数转换到分为单位\r
-        double du = (longitude - intdu * 100) / 60f;\r
-        double last = intdu + du;\r
-        longitude = last;\r
-        intdu = (int) (latitude / 100f); //小数转换到分为单位\r
-        du = (latitude - intdu * 100) / 60f;\r
-        last = intdu + du;\r
-        latitude = last;\r
-\r
-        // 经纬度 保留4位小数点\r
-        DecimalFormat df = new DecimalFormat("#.0000000");\r
-        String strLatitude = df.format(latitude);\r
-        String strLongitude = df.format(longitude);\r
-\r
-        //定位\r
-        StringBuilder sb = new StringBuilder();\r
-        sb.append("GPGGA, location time= " + TimeUtil.getLocalTime() + ", FixedCount=" + locationFixedCount + ", GPSTime=" + utctime + ", Lat("+latname+")=" + Lat + " (" + strLatitude + "), Lon("+lonname+")=" + lon + " (" + strLongitude + "), fixed=" + fixed + ", hdop=" + hdop + ", usedStarts=" + usedStarts);\r
-        ICLogger.i(sb.toString());\r
-        if (Config.LOG_TOFILE)\r
-          ICLogger.logToFile( "GPS", sb.toString());\r
-        //定位了,\r
-        if (hdop != null && hdop.trim().length() > 0 && Float.valueOf(hdop) < ICLocation.MAX_HDOP) {\r
-          locationFixedCount++;\r
-        } else {\r
-          ICLogger.i("HDOP is larger than " + ICLocation.MAX_HDOP + " , skip this location!");\r
-          if (Config.LOG_TOFILE)\r
-            ICLogger.logToFile( "GPS", "HDOP is larger than " + ICLocation.MAX_HDOP + " , skip this location!");\r
-        }\r
-        if (locationFixedCount > MaxFixedTimes) {\r
-               /*\r
-                只有当前GPS已经定位,且location不为空才给 runtime赋值GPS坐标。\r
-                延迟MaxFixedTimes秒后才设置runtime的定位标志,以便稳定坐标值。\r
-              */\r
-          runtime.getLocationInstance().setLocation(Lat, lon);\r
-          runtime.getLocationInstance().setLocationGPS(strLatitude, strLongitude);\r
-          runtime.getLocationInstance().setLocationlatlonName(latname,lonname);\r
-          runtime.getLocationInstance().setUsedStarts(Integer.valueOf(usedStarts.trim()));\r
-          runtime.getLocationInstance().setHod(Float.valueOf(hdop.trim()));\r
-          runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_FIXED);\r
-          ICLogger.i("定位" + locationFixedCount + "次 > " + MaxFixedTimes + ", set LOCATION_FIXED ");\r
-          if (Config.LOG_TOFILE)\r
-            ICLogger.logToFile("GPS", "定位" + locationFixedCount + "次 > " + MaxFixedTimes + ", set LOCATION_FIXED ");\r
-          if (!noStop) {\r
-            stopListen();\r
-          }\r
-        }\r
-        gps_status.locating_status = 1; //fixed\r
-      } else {\r
-        gps_status.locating_status = 0; //notfixed\r
-      }\r
-      gps_status.hdop = Float.valueOf(hdop.trim());\r
-      gps_status.used_gps_numbs = Integer.valueOf(usedStarts.trim());\r
-\r
-\r
-    } else if (nmeastr.startsWith("$GPGSA,")) {\r
-\r
-//    GPGSA编辑\r
-//( 当前卫星信息)\r
-//    例:$GPGSA,A,3,01,20,19,13,,,,,,,,,40.4,24.4,32.2*0A\r
-//    字段0:$GPGSA,语句ID,表明该语句为GPS DOP and Active Satellites(GSA)当前卫星信息\r
-//    字段1:定位模式(选择2D/3D),A=自动选择,M=手动选择\r
-//    字段2:定位类型,1=未定位,2=2D定位,3=3D定位\r
-//    字段3:PRN码(伪随机噪声码),第1信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段4:PRN码(伪随机噪声码),第2信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段5:PRN码(伪随机噪声码),第3信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段6:PRN码(伪随机噪声码),第4信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段7:PRN码(伪随机噪声码),第5信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段8:PRN码(伪随机噪声码),第6信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段9:PRN码(伪随机噪声码),第7信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段10:PRN码(伪随机噪声码),第8信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段11:PRN码(伪随机噪声码),第9信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段12:PRN码(伪随机噪声码),第10信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段13:PRN码(伪随机噪声码),第11信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段14:PRN码(伪随机噪声码),第12信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)\r
-//    字段15:PDOP综合位置精度因子(0.5 - 99.9)\r
-//    字段16:HDOP水平精度因子(0.5 - 99.9)\r
-//    字段17:VDOP垂直精度因子(0.5 - 99.9)\r
-//    字段18:校验值($与*之间的数异或后的值)\r
-\r
-//      String tmplist[]=nmeastr.split(",");\r
-//      String locationmod=tmplist[1];\r
-//      String fixed=tmplist[2];\r
-//      String hdop=tmplist[16];\r
-//      if (!fixed.trim().equals("1")){\r
-//        //定位\r
-//        ICLogger.i("GPGSA fixed="+fixed+",hdop="+hdop);\r
-//      }\r
-    }\r
-  }\r
-\r
-  public void onProviderDisabled(String paramString) {\r
-  }\r
-\r
-  public void onProviderEnabled(String paramString) {\r
-  }\r
-\r
-  @Override\r
-  public void onLocationChanged(Location location) {\r
-\r
-  }\r
-\r
-  public void onStatusChanged(String paramString, int paramInt, Bundle paramBundle) {\r
-  }\r
-\r
-  public boolean gpsColdStart() {\r
-//冷启动\r
-    Bundle bundle = null;\r
-    locationManager.sendExtraCommand("gps", "force_xtra_injection", bundle); //command\r
-    locationManager.sendExtraCommand("gps", "force_time_injection", bundle);\r
-    boolean b1 = locationManager.sendExtraCommand("gps", "delete_aiding_data", bundle);\r
-    return b1;\r
-\r
-  }\r
-\r
-  public boolean gpsWormStart() {\r
-\r
-//温启动\r
-    Bundle bundleWarm = new Bundle();\r
-    bundleWarm.putBoolean("ephemeris", true);\r
-    locationManager.sendExtraCommand("gps", "force_xtra_injection", bundleWarm); //command\r
-    locationManager.sendExtraCommand("gps", "force_time_injection", bundleWarm);\r
-    boolean b2 = locationManager.sendExtraCommand("gps", "delete_aiding_data", bundleWarm);\r
-    return b2;\r
-  }\r
-\r
-  public boolean gpsHotStart() {\r
-//热启动\r
-    Bundle bundleHot = new Bundle();\r
-    bundleHot.putBoolean("almanac", true);\r
-    locationManager.sendExtraCommand("gps", "force_xtra_injection", bundleHot); //command\r
-    locationManager.sendExtraCommand("gps", "force_time_injection", bundleHot);\r
-    boolean b3 = locationManager.sendExtraCommand("gps", "delete_aiding_data", bundleHot);\r
-    return b3;\r
-  }\r
-\r
-\r
-  private final int MSG_WHAT_GPS_FIXED = 300;\r
-  private final int MSG_WHAT_GPS_TIMEOUT = 100;\r
-  private final int MSG_WHAT_GPS_NOSTAR = 200;\r
-  private final int MSG_WHAT_GPS_FIXED_NO_STOP = 400;\r
-\r
-  Handler temHandler = new Handler(new Handler.Callback() {\r
-    @Override\r
-    public boolean handleMessage(Message message) {\r
-\r
-      if (message.what == MSG_WHAT_GPS_TIMEOUT || message.what == MSG_WHAT_GPS_NOSTAR) {\r
-        //no start\r
-        //do nothing\r
-\r
-      } else if (message.what == MSG_WHAT_GPS_FIXED) {\r
-        //fixed\r
-         /*\r
-        只有当前GPS已经定位,且location不为空才给 runtime赋值GPS坐标。\r
-        延迟三秒后才设置runtime的定位标志,以便稳定坐标值。\r
-         */\r
-        runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_FIXED);\r
-\r
-      }\r
-\r
-      if (!noStop) {\r
-        ICLogger.i("handleMessage MSG_WHAT_GPS_TIMEOUT/ MSG_WHAT_GPS_NOSTAR/ MSG_WHAT_GPS_FIXED " + message.what);\r
-\r
-        stopListen();\r
-      }\r
-      return true;\r
-    }\r
-  });\r
-\r
-  private void get3MaxSnrSatellite(ICLocation.GpsSatellitePriv gst) {\r
-\r
-    float snr = gst.getSnr();\r
-    for (int k = 0; k < runtime.getLocationInstance().max3Satellite.size(); k++) {\r
-      if (runtime.getLocationInstance().max3Satellite.get(k).getPrn() == gst.getPrn())\r
-        runtime.getLocationInstance().max3Satellite.remove(k);\r
-    }\r
-    runtime.getLocationInstance().max3Satellite.add(gst);//先添加进来。\r
-\r
-    //从大到小排序\r
-    for (int i = 0; i < runtime.getLocationInstance().max3Satellite.size(); i++) {\r
-      for (int j = i; j < runtime.getLocationInstance().max3Satellite.size(); j++) {\r
-        if (runtime.getLocationInstance().max3Satellite.get(i).getSnr() < runtime.getLocationInstance().max3Satellite.get(j).getSnr()) {\r
-          ICLocation.GpsSatellitePriv ts = runtime.getLocationInstance().max3Satellite.get(j);\r
-          runtime.getLocationInstance().max3Satellite.remove(j);\r
-          runtime.getLocationInstance().max3Satellite.add(i, ts);//大的放前面\r
-        }\r
-      }\r
-    }\r
-    if (runtime.getLocationInstance().max3Satellite.size() > 5) { //超过三个,谁小就删掉\r
-      runtime.getLocationInstance().max3Satellite.remove(5);\r
-    }\r
-\r
-  }\r
-\r
-  //停止定位\r
-  private void stop(int id) {\r
-\r
-    // 经纬度 保留6位小数点\r
-//    DecimalFormat df = new DecimalFormat("#.000000");\r
-//    String strLatitude = df.format(latitude);\r
-//    String strLongitude = df.format(longitude);\r
-//    runtime.setLatitude(strLatitude);\r
-//    runtime.setLongitude(strLongitude);\r
-//\r
-//    ICLogger.i("Location " +runtime.getLocationInstance().getLocationStat().name());\r
-    //发送停止消息\r
-    temHandler.sendEmptyMessage(id);\r
-  }\r
-\r
-  boolean isFrist = true;\r
-\r
-\r
-  public boolean startListen() {\r
-\r
-    if (this.listening == false) {\r
-      Settings.Secure.setLocationProviderEnabled(runtime.getContextProxy().getResolver(), GPS_PROVIDER, true);\r
-\r
-      runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_OPEN);\r
-\r
-      Criteria criteria = new Criteria();\r
-      criteria.setAccuracy(Criteria.ACCURACY_FINE);// 设置为最大精度\r
-      criteria.setAltitudeRequired(false);//不要求海拔信息\r
-      criteria.setBearingRequired(false);// 不要求方位信息\r
-      criteria.setCostAllowed(true);//是否允许付费\r
-      criteria.setPowerRequirement(Criteria.POWER_LOW);// 对电量的要求\r
-\r
-      String provider = locationManager.getBestProvider(criteria, true);\r
-\r
-\r
-      ICLogger.i("GPS StartListen with Provider " + provider);\r
-\r
-      if (Config.LOG_TOFILE) ICLogger.logToFile("GPS", "GPS StartListen with Provider " + provider);\r
-\r
-      this.locationManager.requestLocationUpdates(provider, 0L, 0.0F, this);\r
-\r
-      this.listening = true;\r
-      noSignalCount = 0;\r
-      longitude = 0;\r
-      latitude = 0;\r
-      searchCout = 0;\r
-      locationFixedCount = 0;\r
-      gpsMode = GPS_CURRENT_STATUS.GPS_LISTENING;\r
-//      locationManager.addGpsStatusListener(statusListener);//监听搜星状态\r
-      locationManager.addNmeaListener(this); //监听NMEA 协议数据。\r
-\r
-      //做个热启动\r
-      return true;//gpsHotStart();\r
-    } else {\r
-      ICLogger.i(" location listening, skip !");\r
-\r
-      runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_SEARCHING);\r
-\r
-      if (Config.LOG_TOFILE) ICLogger.logToFile("GPS", " location listening, skip !");\r
-\r
-      return true;\r
-    }\r
-  }\r
-  public boolean isGpsOpening() {\r
-    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);\r
-  }\r
-\r
-  public void stopListen() {\r
-    this.locationManager.removeNmeaListener(this);\r
-    this.locationManager.removeUpdates(this);\r
-    ICLogger.i("stopListen 定位 ");\r
-    if (Config.LOG_TOFILE) ICLogger.logToFile("GPS", "stopListen 定位 ");\r
-    if (listening==true) {\r
-       this.listening = false;\r
-      Settings.Secure.setLocationProviderEnabled(runtime.getContextProxy().getResolver(), GPS_PROVIDER, false);\r
-      ICLogger.i("stopListen 定位 done ");\r
-    }else{\r
-      if (isGpsOpening()){\r
-        Settings.Secure.setLocationProviderEnabled(runtime.getContextProxy().getResolver(), GPS_PROVIDER, false);\r
-        ICLogger.i("flag stoped but gps still opening , stop GPS!");\r
-      }else {\r
-        ICLogger.i("stopListen 定位 already stop skip stopListen");\r
-      }\r
-    }\r
-  }\r
-\r
-  public enum  GPS_CURRENT_STATUS {\r
-    GPS_LISTENING,\r
-    GPS_FIXED,\r
-    GPS_NOTFIXED,\r
-    GPS_TIMEOUT,\r
-    GPS_NOSINGAL,\r
-  }\r
-}\r
+package com.enqualcomm.support;
+
+import android.content.Context;
+import android.location.Criteria;
+import android.location.GpsSatellite;
+import android.location.GpsStatus;
+import android.location.GpsStatus.NmeaListener;
+
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.Settings;
+
+import com.enqualcomm.support.bean.ICLocation;
+import com.enqualcomm.support.bean.Runtime;
+import com.enqualcomm.support.utils.FileOutputUtil;
+import com.enqualcomm.support.utils.ICLogger;
+import com.enqualcomm.support.utils.TimeUtil;
+import com.enqualcomm.support.bean.ICLocation.GPS_locationStatus;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import rx.Single;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Action1;
+
+import static android.location.LocationManager.GPS_PROVIDER;
+
+public class NMEAListener implements NmeaListener, LocationListener {
+  private static boolean listening = false;
+
+  public boolean isListening() {
+    return listening;
+  }
+
+  private LocationManager locationManager;
+  private String locationInfo;
+
+  private double longitude;
+  private double latitude;
+
+  private boolean noStop = false;
+
+
+  private int SearchTimeout = 120;
+  private int noSignalCount = 0;
+  private int searchCout = 0;
+  private GPS_CURRENT_STATUS gpsMode;
+  int numberOfSatellites;
+  Runtime runtime;
+
+  private static int MaxFixedTimes = 3;
+
+  private static int locationFixedCount = 0;
+
+
+  private static location_callback mCallback = null;
+
+  public interface location_callback {
+    public void on_locating_changed(GPS_locationStatus gps_status);
+  }
+
+  public static void set_callback(location_callback callback) {
+    mCallback = callback;
+  }
+
+  private GPS_locationStatus gps_status = new GPS_locationStatus();
+
+  public GPS_locationStatus get_gps_status() {
+    return gps_status;
+  }
+
+
+  public void setNoStop(boolean nostop) {
+    if (Config.noLocationCycle==false)
+      noStop = nostop;
+    else
+        ICLogger.i("skip setNoStop " + nostop);
+    ICLogger.i("setNoStop " + nostop);
+    if (noStop == false) {
+      switch (runtime.getLocationInstance().getWorkingMod()) {
+        case ICLocation.CUSTOM_MOD:
+        case ICLocation.CUSTOM_MOD8_GPS:
+        case ICLocation.EMERGNECY_MOD:
+        case ICLocation.REALTIME_MOD:
+          //GPS 定位模式不关闭GPS,防止 1分钟定位超时后,重新关闭开启GPS。
+          //不给GPS继续定位的机会,造成第一次定位困难!
+          break;
+        case ICLocation.LOWPOWER_MOD:
+        case ICLocation.NORMAL_MOD:
+        case ICLocation.CUSTOM_MOD8_WIFI:
+        default:
+          ICLogger.i("非GPS定位模式,关闭GPS");
+          //非GPS定位模式的话,需要关闭GPS。
+          stopListen();
+          break;
+      }
+
+    }
+  }
+
+  public NMEAListener(LocationManager paramLocationManager, Runtime paramRuntime) {
+    this.locationManager = paramLocationManager;
+    this.runtime = paramRuntime;
+  }
+
+  static int satindex = 0;
+
+  public void onNmeaReceived(long paramLong, String nmeastr) {
+//    EqcAlgorithmNative.native_EqcAlgorithmMethod5(paramString);
+//    ICLogger.i("Nmea :"+nmeastr+" "+paramLong);
+
+    if (Config.LOG_TOFILE)
+      ICLogger.logToFile("Nmea", nmeastr);
+
+    if (nmeastr.startsWith("$RD_RSSI")) {
+        //每组NMEA数据的头,只适用于 SL8521E,9820E
+        gps_status.numSatelliteList.clear();
+        gps_status.search_time_cost = searchCout;
+        runtime.getLocationInstance().numSatelliteList.clear(); //清除 SNR >0的卫星
+        runtime.getLocationInstance().max3Satellite.clear(); //清除 最大3个星值
+    }
+
+    if (nmeastr.startsWith("$GPVTG")) {
+      //每组NMEA数据的尾,只适用于 SL8521E,9820E
+      searchCout++;
+      //最后一页,打印搜星情况,并作一些判断。
+      StringBuilder sb = new StringBuilder();
+      sb.append("搜索" + searchCout + "次,搜索到卫星个数" + gps_status.satlite_numbss + ", [SNR>0] =" + runtime.getLocationInstance().numSatelliteList.size());
+      sb.append(", Max 5 SNR [");
+      for (int i = 0; i < runtime.getLocationInstance().max3Satellite.size(); i++) {
+        sb.append(runtime.getLocationInstance().max3Satellite.get(i).getSnr() + ",");
+      }
+      sb.append("]");
+      if (Config.LOG_TOFILE)
+        ICLogger.logToFile( "GPS", sb.toString());
+
+      ICLogger.i(sb.toString());
+      // 卫星总数小于2 ,或者 snr小于20
+      if (runtime.getLocationInstance().numSatelliteList.size() < 3 && (runtime.getLocationInstance().max3Satellite.size() > 0 ? (runtime.getLocationInstance().max3Satellite.get(0).getSnr() < 20 ? true : false) : true)) {
+        noSignalCount++;
+      }else{
+        noSignalCount=0;//只要有一次满足有信号,则重新开始计数。
+      }
+
+
+      StringBuilder sb2 = new StringBuilder();
+      if (!noStop) {
+        if (searchCout > ICLocation.MAX_GPS_SEARCH_TIMEOUT) {
+          sb2.append(" 搜索" + searchCout + "次未定位,超过" + ICLocation.MAX_GPS_SEARCH_TIMEOUT + "限制退出GPS定位");
+
+          runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_GPS_TIEMOUT);
+
+          stop(MSG_WHAT_GPS_TIMEOUT);
+        }
+        if (noSignalCount > ICLocation.MAX_GPS_NOSIGNAL_COUNT) {
+          sb2.append(" 搜索" + searchCout + "次,超过" + noSignalCount + "次没有收到星,退出GPS定位");
+          runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_GPS_TIEMOUT);
+          stop(MSG_WHAT_GPS_NOSTAR);
+        }
+      }
+      ICLogger.i(sb2.toString());
+      if (Config.LOG_TOFILE)
+        ICLogger.logToFile("GPS", sb2.toString());
+
+
+      if (mCallback != null)
+        mCallback.on_locating_changed(get_gps_status());
+    }
+    if (nmeastr.startsWith("$GPGLL,") ||nmeastr.startsWith("$GNGLL,")) {
+      String tmplist[] = nmeastr.split(",");
+//      GPGLL编辑
+//(地理定位信息)
+//      例:$GPGLL,4250.5589,S,14718.5084,E,092204.999,A*2D
+//      字段0:$GPGLL,语句ID,表明该语句为Geographic Position(GLL)地理定位信息
+//      字段1:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
+//      字段2:纬度N(北纬)或S(南纬)
+//      字段3:经度dddmm.mmmm,度分格式(前导位数不足则补0)
+//      字段4:经度E(东经)或W(西经)
+//      字段5:UTC时间,hhmmss.sss格式
+//      字段6:状态,A=定位,V=未定位
+//      字段7:校验值($与*之间的数异或后的值)
+      String Lat = tmplist[1];
+      String lon = tmplist[3];
+      String fixed = tmplist[6];
+//      ICLogger.i("GPGLL Lat="+Lat+",Lon="+lon+",fixed="+fixed);
+
+    } else if (nmeastr.startsWith("$GPRMC,")||nmeastr.startsWith("$GNRMC,")) {
+//      GPRMC编辑
+//(推荐定位信息数据格式)
+//      例:$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
+//      字段0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
+//      字段1:UTC时间,hhmmss.sss格式
+//      字段2:状态,A=定位,V=未定位
+//      字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
+//      字段4:纬度N(北纬)或S(南纬)
+//      字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
+//      字段6:经度E(东经)或W(西经)
+//      字段7:速度,节,Knots
+//      字段8:方位角,度
+//      字段9:UTC日期,DDMMYY格式
+//      字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
+//      字段11:磁偏角方向,E=东W=西
+//      字段12:模式,A=自动,D=差分,E=估测,N=数据无效(3.0协议内容)
+//      字段13:校验值($与*之间的数异或后的值)
+      String tmplist[] = nmeastr.split(",");
+      String utctime = tmplist[1];
+      String Lat = tmplist[3];
+      String lon = tmplist[5];
+      String fixed = tmplist[2];
+      String speed = tmplist[7];
+//      ICLogger.i("GPRMC GPSTime="+utctime+",Lat="+Lat+",Lon="+lon+",fixed="+fixed+",speed="+speed);
+//      if (Config.LOG_TOFILE)
+//        FileOutputUtil.fileOutput(this.runtime.getCacheDir(), "GPS", "GPRMC GPSTime="+utctime+",Lat="+Lat+",Lon="+lon+",fixed="+fixed+",speed="+speed);
+      if (fixed.trim().equals("A")) {
+        if (speed.trim().isEmpty()) speed = "0.0";
+        runtime.getLocationInstance().setSpeed(Float.valueOf(speed));
+      }
+
+
+    } else if (nmeastr.startsWith("$GPGSV,")||nmeastr.startsWith("$GLGSV,")||nmeastr.startsWith("$GAGSV,")||nmeastr.startsWith("$GBGSV,")||nmeastr.startsWith("$BDGSV,")) {
+
+//    GPGSV编辑
+//            (可见卫星信息)
+//    例:$GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,069,,13,32,252,45*70
+//    字段0:$GPGSV,语句ID,表明该语句为GPS Satellites in View(GSV)可见卫星信息
+//    字段1:本次GSV语句的总数目(1 - 3)
+//    字段2:本条GSV语句是本次GSV语句的第几条(1 - 3)
+//    字段3:当前可见卫星总数(00 - 12)(前导位数不足则补0)
+//    字段4:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)
+//    字段5:卫星仰角(00 - 90)度(前导位数不足则补0)
+//    字段6:卫星方位角(00 - 359)度(前导位数不足则补0)
+//    字段7:信噪比(00-99)dbHz
+//    字段8:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)
+//    字段9:卫星仰角(00 - 90)度(前导位数不足则补0)
+//    字段10:卫星方位角(00 - 359)度(前导位数不足则补0)
+//    字段11:信噪比(00-99)dbHz
+//    字段12:PRN 码(伪随机噪声码)(01 - 32)(前导位数不足则补0)
+//    字段13:卫星仰角(00 - 90)度(前导位数不足则补0)
+////    字段14:卫星方位角(00 - 359)度(前导位数不足则补0)
+////    字段15:信噪比(00-99)dbHz
+//    字段16:校验值($与*之间的数异或后的值)
+
+      String tmplist[] = nmeastr.split(",");
+      int maxPageCount = 0;
+      int currentPage = 0;
+      int SatlitesCount = 0;
+
+      try {
+        maxPageCount = Integer.valueOf(tmplist[1]);
+      } catch (Exception e) {
+      }
+      try {
+        currentPage = Integer.valueOf(tmplist[2]);
+      } catch (Exception e) {
+      }
+      try {
+        SatlitesCount = Integer.valueOf(tmplist[3]);
+      } catch (Exception e) {
+      }
+      if (maxPageCount > 0 && currentPage == 1) {
+        //第一页把数组初始化一遍。
+        satindex = 0;
+        gps_status.satlite_numbss = SatlitesCount;
+      }
+      int satcount = (tmplist.length - 4) / 4;
+//      ICLogger.i("Nmea :"+nmeastr+" "+satcount);
+      runtime.getLocationInstance().set_adding_satlite_flag(true);
+      for (int i = 0; i < satcount; i++) {
+        satindex++;
+        String prn = tmplist[i * 4 + 4];
+        String snr = tmplist[i * 4 + 4 + 3];
+        if (snr.contains("*")) {
+          snr = snr.substring(0, snr.indexOf("*"));
+        }
+        if (snr.trim().isEmpty()) {
+          snr = "0";
+        }
+//        ICLogger.i("Sat=" + satindex + ",prn=" + prn + ",snr=" + snr);
+
+        int intprn = 0;
+        try {
+          intprn = Integer.valueOf(prn);
+        } catch (Exception e) {
+        }
+        float floatsnr = 0;
+        try {
+          floatsnr = Float.valueOf(snr);
+        } catch (Exception e) {
+        }
+        if (floatsnr > 0) {
+          //排序取得最大3个SNR
+          get3MaxSnrSatellite(new ICLocation.GpsSatellitePriv(intprn, floatsnr));
+          runtime.getLocationInstance().numSatelliteList.add(new ICLocation.GpsSatellitePriv(intprn, floatsnr));
+          gps_status.numSatelliteList.add(new ICLocation.GpsSatellitePriv(intprn, floatsnr));
+        }
+      }
+
+      runtime.getLocationInstance().set_adding_satlite_flag(false);
+
+    } else if (nmeastr.startsWith("$GPGGA,")||nmeastr.startsWith("$GNGGA,")) {
+
+//    GPGGA编辑
+//(定位信息)
+//    例:$GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,12.2,M,19.7,M,,0000*1F
+//    字段0:$GPGGA,语句ID,表明该语句为Global Positioning System Fix Data(GGA)GPS定位信息
+//    字段1:UTC 时间,hhmmss.sss,时分秒格式
+//    字段2:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
+//    字段3:纬度N(北纬)或S(南纬)
+//    字段4:经度dddmm.mmmm,度分格式(前导位数不足则补0)
+//    字段5:经度E(东经)或W(西经)
+//    字段6:GPS状态,0=不可用(FIX NOT valid),1=单点定位(GPS FIX),2=差分定位(DGPS),3=无效PPS,4=实时差分定位(RTK FIX),5=RTK FLOAT,6=正在估算
+//    字段7:正在使用的卫星数量(00 - 12)(前导位数不足则补0)
+//    字段8:HDOP水平精度因子(0.5 - 99.9)
+//    字段9:海拔高度(-9999.9 - 99999.9)
+//    字段10:单位:M(米)
+//    字段11:地球椭球面相对大地水准面的高度 WGS84水准面划分
+//    字段12:WGS84水准面划分单位:M(米)
+//    字段13:差分时间(从接收到差分信号开始的秒数,如果不是差分定位将为空)
+//    字段14:差分站ID号0000 - 1023(前导位数不足则补0,如果不是差分定位将为空)
+//    字段15:校验值($与*之间的数异或后的值)
+
+      String tmplist[] = nmeastr.split(",");
+      String utctime = tmplist[1];
+      String Lat = tmplist[2];
+      String lon = tmplist[4];
+      String latname= tmplist[3];
+      String lonname=tmplist[5];
+      String fixed = tmplist[6];
+      String usedStarts = tmplist[7];
+      String hdop = tmplist[8];
+
+
+      if ((fixed.trim().equals("1")) || (fixed.trim().equals("2")) || (fixed.trim().equals("6"))) {
+
+
+        // 转换GPS坐标为度,以便在各种应用中可以方便查找。
+        try {
+          latitude = Double.valueOf(Lat);
+          longitude = Double.valueOf(lon);
+        } catch (Exception e){}
+        // 转换单位,从分转换到度
+
+        double intdu = (int) (longitude / 100f); //小数转换到分为单位
+        double du = (longitude - intdu * 100) / 60f;
+        double last = intdu + du;
+        longitude = last;
+        intdu = (int) (latitude / 100f); //小数转换到分为单位
+        du = (latitude - intdu * 100) / 60f;
+        last = intdu + du;
+        latitude = last;
+
+        // 经纬度 保留4位小数点
+        DecimalFormat df = new DecimalFormat("#.0000000");
+        String strLatitude = df.format(latitude);
+        String strLongitude = df.format(longitude);
+
+        //定位
+        StringBuilder sb = new StringBuilder();
+        sb.append("GPGGA, location time= " + TimeUtil.getLocalTime() + ", FixedCount=" + locationFixedCount + ", GPSTime=" + utctime + ", Lat("+latname+")=" + Lat + " (" + strLatitude + "), Lon("+lonname+")=" + lon + " (" + strLongitude + "), fixed=" + fixed + ", hdop=" + hdop + ", usedStarts=" + usedStarts);
+        ICLogger.i(sb.toString());
+        if (Config.LOG_TOFILE)
+          ICLogger.logToFile( "GPS", sb.toString());
+        //定位了,
+        if (hdop != null && hdop.trim().length() > 0 && Float.valueOf(hdop) < ICLocation.MAX_HDOP) {
+          locationFixedCount++;
+        } else {
+          ICLogger.i("HDOP is larger than " + ICLocation.MAX_HDOP + " , skip this location!");
+          if (Config.LOG_TOFILE)
+            ICLogger.logToFile( "GPS", "HDOP is larger than " + ICLocation.MAX_HDOP + " , skip this location!");
+        }
+        if (locationFixedCount > MaxFixedTimes) {
+               /*
+                只有当前GPS已经定位,且location不为空才给 runtime赋值GPS坐标。
+                延迟MaxFixedTimes秒后才设置runtime的定位标志,以便稳定坐标值。
+              */
+          runtime.getLocationInstance().setLocation(Lat, lon);
+          runtime.getLocationInstance().setLocationGPS(strLatitude, strLongitude);
+          runtime.getLocationInstance().setLocationlatlonName(latname,lonname);
+          runtime.getLocationInstance().setUsedStarts(Integer.valueOf(usedStarts.trim()));
+          runtime.getLocationInstance().setHod(Float.valueOf(hdop.trim()));
+          runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_FIXED);
+          ICLogger.i("定位" + locationFixedCount + "次 > " + MaxFixedTimes + ", set LOCATION_FIXED ");
+          if (Config.LOG_TOFILE)
+            ICLogger.logToFile("GPS", "定位" + locationFixedCount + "次 > " + MaxFixedTimes + ", set LOCATION_FIXED ");
+          if (!noStop) {
+            stopListen();
+          }
+        }
+        gps_status.locating_status = 1; //fixed
+      } else {
+        gps_status.locating_status = 0; //notfixed
+      }
+      try {
+        gps_status.hdop = Float.valueOf(hdop.trim());
+        gps_status.used_gps_numbs = Integer.valueOf(usedStarts.trim());
+      } catch (Exception e) {
+      }
+
+    } else if (nmeastr.startsWith("$GPGSA,")||nmeastr.startsWith("$GNGSA,")) {
+
+//    GPGSA编辑
+//( 当前卫星信息)
+//    例:$GPGSA,A,3,01,20,19,13,,,,,,,,,40.4,24.4,32.2*0A
+//    字段0:$GPGSA,语句ID,表明该语句为GPS DOP and Active Satellites(GSA)当前卫星信息
+//    字段1:定位模式(选择2D/3D),A=自动选择,M=手动选择
+//    字段2:定位类型,1=未定位,2=2D定位,3=3D定位
+//    字段3:PRN码(伪随机噪声码),第1信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段4:PRN码(伪随机噪声码),第2信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段5:PRN码(伪随机噪声码),第3信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段6:PRN码(伪随机噪声码),第4信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段7:PRN码(伪随机噪声码),第5信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段8:PRN码(伪随机噪声码),第6信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段9:PRN码(伪随机噪声码),第7信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段10:PRN码(伪随机噪声码),第8信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段11:PRN码(伪随机噪声码),第9信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段12:PRN码(伪随机噪声码),第10信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段13:PRN码(伪随机噪声码),第11信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段14:PRN码(伪随机噪声码),第12信道正在使用的卫星PRN码编号(00)(前导位数不足则补0)
+//    字段15:PDOP综合位置精度因子(0.5 - 99.9)
+//    字段16:HDOP水平精度因子(0.5 - 99.9)
+//    字段17:VDOP垂直精度因子(0.5 - 99.9)
+//    字段18:校验值($与*之间的数异或后的值)
+
+//      String tmplist[]=nmeastr.split(",");
+//      String locationmod=tmplist[1];
+//      String fixed=tmplist[2];
+//      String hdop=tmplist[16];
+//      if (!fixed.trim().equals("1")){
+//        //定位
+//        ICLogger.i("GPGSA fixed="+fixed+",hdop="+hdop);
+//      }
+    }
+  }
+
+  public void onProviderDisabled(String paramString) {
+  }
+
+  public void onProviderEnabled(String paramString) {
+  }
+
+  @Override
+  public void onLocationChanged(Location location) {
+
+  }
+
+  public void onStatusChanged(String paramString, int paramInt, Bundle paramBundle) {
+  }
+
+  public boolean gpsColdStart() {
+//冷启动
+    Bundle bundle = null;
+    locationManager.sendExtraCommand("gps", "force_xtra_injection", bundle); //command
+    locationManager.sendExtraCommand("gps", "force_time_injection", bundle);
+    boolean b1 = locationManager.sendExtraCommand("gps", "delete_aiding_data", bundle);
+    return b1;
+
+  }
+
+  public boolean gpsWormStart() {
+
+//温启动
+    Bundle bundleWarm = new Bundle();
+    bundleWarm.putBoolean("ephemeris", true);
+    locationManager.sendExtraCommand("gps", "force_xtra_injection", bundleWarm); //command
+    locationManager.sendExtraCommand("gps", "force_time_injection", bundleWarm);
+    boolean b2 = locationManager.sendExtraCommand("gps", "delete_aiding_data", bundleWarm);
+    return b2;
+  }
+
+  public boolean gpsHotStart() {
+//热启动
+    Bundle bundleHot = new Bundle();
+    bundleHot.putBoolean("almanac", true);
+    locationManager.sendExtraCommand("gps", "force_xtra_injection", bundleHot); //command
+    locationManager.sendExtraCommand("gps", "force_time_injection", bundleHot);
+    boolean b3 = locationManager.sendExtraCommand("gps", "delete_aiding_data", bundleHot);
+    return b3;
+  }
+
+
+  private final int MSG_WHAT_GPS_FIXED = 300;
+  private final int MSG_WHAT_GPS_TIMEOUT = 100;
+  private final int MSG_WHAT_GPS_NOSTAR = 200;
+  private final int MSG_WHAT_GPS_FIXED_NO_STOP = 400;
+
+  Handler temHandler = new Handler(new Handler.Callback() {
+    @Override
+    public boolean handleMessage(Message message) {
+
+      if (message.what == MSG_WHAT_GPS_TIMEOUT || message.what == MSG_WHAT_GPS_NOSTAR) {
+        //no start
+        //do nothing
+
+      } else if (message.what == MSG_WHAT_GPS_FIXED) {
+        //fixed
+         /*
+        只有当前GPS已经定位,且location不为空才给 runtime赋值GPS坐标。
+        延迟三秒后才设置runtime的定位标志,以便稳定坐标值。
+         */
+        runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_FIXED);
+
+      }
+
+      if (!noStop) {
+        ICLogger.i("handleMessage MSG_WHAT_GPS_TIMEOUT/ MSG_WHAT_GPS_NOSTAR/ MSG_WHAT_GPS_FIXED " + message.what);
+
+        stopListen();
+      }
+      return true;
+    }
+  });
+
+  private void get3MaxSnrSatellite(ICLocation.GpsSatellitePriv gst) {
+
+    float snr = gst.getSnr();
+    for (int k = 0; k < runtime.getLocationInstance().max3Satellite.size(); k++) {
+      if (runtime.getLocationInstance().max3Satellite.get(k).getPrn() == gst.getPrn())
+        runtime.getLocationInstance().max3Satellite.remove(k);
+    }
+    runtime.getLocationInstance().max3Satellite.add(gst);//先添加进来。
+
+    //从大到小排序
+    for (int i = 0; i < runtime.getLocationInstance().max3Satellite.size(); i++) {
+      for (int j = i; j < runtime.getLocationInstance().max3Satellite.size(); j++) {
+        if (runtime.getLocationInstance().max3Satellite.get(i).getSnr() < runtime.getLocationInstance().max3Satellite.get(j).getSnr()) {
+          ICLocation.GpsSatellitePriv ts = runtime.getLocationInstance().max3Satellite.get(j);
+          runtime.getLocationInstance().max3Satellite.remove(j);
+          runtime.getLocationInstance().max3Satellite.add(i, ts);//大的放前面
+        }
+      }
+    }
+    if (runtime.getLocationInstance().max3Satellite.size() > 5) { //超过三个,谁小就删掉
+      runtime.getLocationInstance().max3Satellite.remove(5);
+    }
+
+  }
+
+  //停止定位
+  private void stop(int id) {
+
+    // 经纬度 保留6位小数点
+//    DecimalFormat df = new DecimalFormat("#.000000");
+//    String strLatitude = df.format(latitude);
+//    String strLongitude = df.format(longitude);
+//    runtime.setLatitude(strLatitude);
+//    runtime.setLongitude(strLongitude);
+//
+//    ICLogger.i("Location " +runtime.getLocationInstance().getLocationStat().name());
+    //发送停止消息
+    temHandler.sendEmptyMessage(id);
+  }
+
+  boolean isFrist = true;
+
+
+  public boolean startListen() {
+
+    if (this.listening == false) {
+      Settings.Secure.setLocationProviderEnabled(runtime.getContextProxy().getResolver(), GPS_PROVIDER, true);
+
+      runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_OPEN);
+
+      Criteria criteria = new Criteria();
+      criteria.setAccuracy(Criteria.ACCURACY_FINE);// 设置为最大精度
+      criteria.setAltitudeRequired(false);//不要求海拔信息
+      criteria.setBearingRequired(false);// 不要求方位信息
+      criteria.setCostAllowed(true);//是否允许付费
+      criteria.setPowerRequirement(Criteria.POWER_LOW);// 对电量的要求
+
+      String provider = locationManager.getBestProvider(criteria, true);
+
+
+      ICLogger.i("GPS StartListen with Provider " + provider);
+
+      if (Config.LOG_TOFILE) ICLogger.logToFile("GPS", "GPS StartListen with Provider " + provider);
+
+      this.locationManager.requestLocationUpdates(provider, 0L, 0.0F, this);
+
+      this.listening = true;
+      noSignalCount = 0;
+      longitude = 0;
+      latitude = 0;
+      searchCout = 0;
+      locationFixedCount = 0;
+      gpsMode = GPS_CURRENT_STATUS.GPS_LISTENING;
+//      locationManager.addGpsStatusListener(statusListener);//监听搜星状态
+      locationManager.addNmeaListener(this); //监听NMEA 协议数据。
+
+      //做个热启动
+      return true;//gpsHotStart();
+    } else {
+      ICLogger.i(" location listening, skip !");
+
+      runtime.getLocationInstance().setLocationStat(ICLocation.LOCATION_STAT.LOCATION_SEARCHING);
+
+      if (Config.LOG_TOFILE) ICLogger.logToFile("GPS", " location listening, skip !");
+
+      return true;
+    }
+  }
+  public boolean isGpsOpening() {
+    return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+  }
+
+  public void stopListen() {
+    this.locationManager.removeNmeaListener(this);
+    this.locationManager.removeUpdates(this);
+    ICLogger.i("stopListen 定位 ");
+    if (Config.LOG_TOFILE) ICLogger.logToFile("GPS", "stopListen 定位 ");
+    if (listening==true) {
+       this.listening = false;
+      Settings.Secure.setLocationProviderEnabled(runtime.getContextProxy().getResolver(), GPS_PROVIDER, false);
+      ICLogger.i("stopListen 定位 done ");
+    }else{
+      if (isGpsOpening()){
+        Settings.Secure.setLocationProviderEnabled(runtime.getContextProxy().getResolver(), GPS_PROVIDER, false);
+        ICLogger.i("flag stoped but gps still opening , stop GPS!");
+      }else {
+        ICLogger.i("stopListen 定位 already stop skip stopListen");
+      }
+    }
+  }
+
+  public enum  GPS_CURRENT_STATUS {
+    GPS_LISTENING,
+    GPS_FIXED,
+    GPS_NOTFIXED,
+    GPS_TIMEOUT,
+    GPS_NOSINGAL,
+  }
+}