├── .gitignore ├── README.md ├── app ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── tonker │ │ └── gnss │ │ ├── activity │ │ └── MainActivity.java │ │ ├── constant │ │ └── Constant.java │ │ ├── file │ │ ├── FileSelectView.java │ │ ├── NmeaConsumer.java │ │ ├── NmeaProducer.java │ │ ├── NmeaStorage.java │ │ ├── OpenFileDialog.java │ │ └── OpenFileDialogCallback.java │ │ ├── fragment │ │ ├── FragmentTabAdapter.java │ │ ├── MessageCallbacks.java │ │ ├── MessageFragment.java │ │ ├── OrientationCallbacks.java │ │ ├── OrientationFragment.java │ │ ├── SignalCallbacks.java │ │ ├── SignalFragment.java │ │ ├── TimeCallbacks.java │ │ └── TimeFragment.java │ │ ├── graphics │ │ ├── BarChart.java │ │ ├── BarChartCallbacks.java │ │ ├── BdsBarChart.java │ │ ├── BdsBarChartCallbacks.java │ │ ├── SatelliteView.java │ │ ├── SatelliteViewCallbacks.java │ │ ├── SignalScaleBar.java │ │ └── SignalScaleBarCallbacks.java │ │ └── location │ │ ├── LocationAdapter.java │ │ ├── MySatellite.java │ │ └── SatelliteAdapter.java │ └── res │ ├── drawable-hdpi │ ├── feedback_title.9.png │ ├── filedialog_3gp.png │ ├── filedialog_apk.png │ ├── filedialog_bmp.png │ ├── filedialog_cab.png │ ├── filedialog_chm.png │ ├── filedialog_doc.png │ ├── filedialog_folder.jpg │ ├── filedialog_folder_up.jpg │ ├── filedialog_jpg.png │ ├── filedialog_mp3.jpg │ ├── filedialog_mp4.png │ ├── filedialog_ppt.png │ ├── filedialog_root.jpg │ ├── filedialog_swf.png │ ├── filedialog_tif.png │ ├── filedialog_txt.png │ ├── filedialog_unknown.gif │ ├── filedialog_wav.jpg │ ├── filedialog_zip.png │ ├── gnss_assist.png │ ├── menu_exit_alert.png │ ├── tab_message.png │ ├── tab_orientation.png │ ├── tab_orientation_compass.jpg │ ├── tab_select.png │ ├── tab_select_down.png │ ├── tab_signal.png │ ├── tab_time.png │ ├── title_back_normal.png │ ├── title_back_pressed.png │ ├── title_next_normal.png │ └── title_next_pressed.png │ ├── drawable │ ├── border.xml │ ├── switch_border_pressed.xml │ ├── switch_buttom_selector.xml │ ├── tab_background.xml │ ├── title_back_button_selector.xml │ └── title_next_button_selector.xml │ ├── layout │ ├── filedialog_item.xml │ ├── main.xml │ ├── tab_a.xml │ ├── tab_b.xml │ ├── tab_c.xml │ ├── tab_d.xml │ └── title_bar.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── drawables.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── import-summary.txt ├── screenshots ├── 01.png ├── 02.png ├── 03.png ├── 04.png └── app-debug.apk └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | #*.apk 3 | #*.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | #Gradle files 16 | .gradle 17 | /.gradle/2.2.1/taskArtifacts/ 18 | .gradle/2.2.1/taskArtifacts/ 19 | build/ 20 | 21 | # Local configuration file (sdk path, etc) 22 | local.properties 23 | 24 | # Proguard folder generated by Eclipse 25 | proguard/ 26 | 27 | # Log Files 28 | *.log 29 | 30 | signing.properties 31 | CMakeLists.txt 32 | 33 | #IntelliJ IDEA 34 | .idea 35 | .idea/ 36 | *.iml 37 | 38 | # OS-specific files 39 | .DS_Store 40 | .DS_Store? 41 | ._* 42 | .Spotlight-V100 43 | .Trashes 44 | ehthumbs.db 45 | Thumbs.db 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GnssAssist 2 | 一个用于获取、分析和展示手机端导航数据的app 3 | 4 | 这个app主要用于获取手机中到导航数据,分析并进行展示。 5 | 现在主要包括了四个界面: 6 | 7 | - 信号强度展示界面;此界面中分成了上下两部分,上面显示gps和glonass,下面显示bds和Galileo;未定位的是灰色,已定位的是蓝色; 8 | 9 | ![信号强度展示界面](https://github.com/newtonker/GnssAssist/raw/master/screenshots/01.png) 10 | 11 | - 卫星方位展示界面;此界面主要显示了卫星的方位信息。同时显示了可见卫星数目和已连接卫星数目; 12 | 13 | ![卫星方位展示界面](https://github.com/newtonker/GnssAssist/raw/master/screenshots/02.png) 14 | 15 | - 定位参数展示界面;此界面主要显示了卫星定位后的参数信息。 16 | 17 | ![定位参数展示界面](https://github.com/newtonker/GnssAssist/raw/master/screenshots/03.png) 18 | 19 | - 导航协议展示界面;此界面主要显示NEMA-0183协议,同时可以保存和查看。 20 | 21 | ![导航协议展示界面](https://github.com/newtonker/GnssAssist/raw/master/screenshots/04.png) 22 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.tonker.gnss" 9 | minSdkVersion 14 10 | targetSdkVersion 23 11 | } 12 | 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.android.support:support-v4:23.1.1' 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 30 | 31 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.activity; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.location.Location; 7 | import android.location.LocationManager; 8 | import android.os.Bundle; 9 | import android.support.v4.app.FragmentActivity; 10 | import android.support.v4.app.FragmentManager; 11 | import android.widget.ImageView; 12 | import android.widget.RadioGroup; 13 | 14 | import com.tonker.gnss.R; 15 | import com.tonker.gnss.fragment.*; 16 | import com.tonker.gnss.constant.Constant; 17 | import com.tonker.gnss.location.LocationAdapter; 18 | 19 | /** 20 | * 这一个类是开机动画执行完后要执行的类,该类主要用来加载四个标签页,开启获取定位类实例,显示菜单等。 21 | * @author newtonker 22 | * @date 2014-06-10 23 | */ 24 | public class MainActivity extends FragmentActivity 25 | { 26 | //管理Fragment类的实例及四个Fragment 27 | private SignalFragment mSignalFragment; 28 | private OrientationFragment mOrientationFragment; 29 | private TimeFragment mTimeFragment; 30 | private MessageFragment mMessageFragment; 31 | 32 | //获取定位类的实例 33 | private LocationManager mLocationManager; 34 | private Location mLocation; 35 | private LocationAdapter mLocationAdapter; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) 39 | { 40 | super.onCreate(savedInstanceState); 41 | //加载主界面 42 | setContentView(R.layout.main); 43 | 44 | //标题栏TextView 45 | ImageView mBackButton = (ImageView) findViewById(R.id.title_back_btn); 46 | ImageView mNextButton = (ImageView) findViewById(R.id.title_next_btn); 47 | //获取管理Fragment的实例 48 | FragmentManager mFragmentManager = this.getSupportFragmentManager(); 49 | //创建四个Fragment 50 | mSignalFragment = new SignalFragment(); 51 | mOrientationFragment = new OrientationFragment(); 52 | mTimeFragment = new TimeFragment(); 53 | mMessageFragment = new MessageFragment(); 54 | //获取单选按钮组 55 | RadioGroup mRadioGroup = (RadioGroup) findViewById(R.id.group); 56 | //创建FragmentTabAdapter实例,该实例用于控制四个标签页的切换 57 | new FragmentTabAdapter(mBackButton, mNextButton, mFragmentManager, mSignalFragment, mOrientationFragment, mTimeFragment, mMessageFragment, mRadioGroup); 58 | 59 | // 获取系统的LocationManager 60 | mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); 61 | // 获取位置信息, 如果不设置查询条件,getLastKnowLocation方法传入参数LocationManager.GPS_PROVIDER 62 | mLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); 63 | } 64 | 65 | @Override 66 | protected void onStart() 67 | { 68 | super.onStart(); 69 | //要先让Fragment建立起来后才能设置进行回调,因此放在onStart中执行 70 | if (null == mLocationAdapter) 71 | { 72 | mLocationAdapter = new LocationAdapter(mSignalFragment, mOrientationFragment, mTimeFragment, mMessageFragment, mLocationManager, mLocation); 73 | } 74 | } 75 | 76 | /** 77 | * 点击后退键时,弹出退出对话框 78 | */ 79 | @Override 80 | public void onBackPressed() 81 | { 82 | //获取退出对话框实例,同时设置确定和取消按钮 83 | new AlertDialog.Builder(this).setTitle(Constant.EXIT_TO_CONFIRM).setIcon(R.drawable.menu_exit_alert).setPositiveButton(Constant.EXIT_CONFIRM, new DialogInterface.OnClickListener() 84 | { 85 | @Override 86 | public void onClick(DialogInterface dialog, int which) 87 | { 88 | MainActivity.this.finish(); 89 | } 90 | }).setNegativeButton(Constant.EXIT_CANCEL, new DialogInterface.OnClickListener() 91 | { 92 | @Override 93 | public void onClick(DialogInterface dialog, int which) 94 | { 95 | dialog.dismiss(); 96 | } 97 | }).create().show(); 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/constant/Constant.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.constant; 2 | 3 | /** 4 | * 这是一个接口,用来定义一些常量,在程序中使用时便于统一管理 5 | */ 6 | public class Constant 7 | { 8 | //菜单退出时使用 9 | public final static String EXIT_TO_CONFIRM = "确认退出?"; 10 | public final static String EXIT_CONFIRM = "确认"; 11 | public final static String EXIT_CANCEL = "取消"; 12 | 13 | //SignalFragment中用到的常量 14 | public static final String GNSS_SWITCH_ON = "GNSS已打开"; 15 | public static final String GNSS_SWITCH_OFF = "GNSS已关闭"; 16 | 17 | //TimeFragment中用到的常量 18 | public final static String UPDATE_DATE_FORMAT = "update_date_format"; 19 | public final static String UPDATE_TIME_FORMAT = "update_time_format"; 20 | public final static String UPDATE_LONGITUDE_FORMAT = "update_longitude_format"; 21 | public final static String UPDATE_ACCURACY_FORMAT = "update_accuracy_format"; 22 | public final static String UPDATE_ALTITUDE_FORMAT = "update_altitude_format"; 23 | public final static String UPDATE_SPEED_FORMAT = "update_speed_format"; 24 | public final static String UPDATE_BEARING_FORMAT = "update_bearing_format"; 25 | public final static String UPDATE_DEFAULT_FORMAT = "update_default_format"; 26 | public final static String INTEGER_FORMAT = "%.0f"; 27 | public final static String DECIMALS_FORMAT = "%.1f"; 28 | 29 | //MessageFragment中使用到的常量,设置TextView所能接受的最大行数,文件保存路径等 30 | public final static int MAX_LINE = 60; 31 | public final static int STRING_BUILDER_CAPATICY = 1000; 32 | public final static String MESSAGE_SAVE = "保存"; 33 | public final static String MESSAGE_CANCEL_SAVE = "取消"; 34 | public final static String MESSAGE_PAUSE = "暂停"; 35 | public final static String MESSAGE_CONTINUE = "继续"; 36 | public final static String FILE_SAVE_DIR = "/gnss_assist/files/"; 37 | public final static String FILE_SAVE_START = "文件保存为:"; 38 | public final static String FILE_SAVE_STOP = "结束保存"; 39 | public final static String CREATE_DIR_FAILED = "创建存储路径失败"; 40 | public final static String CREATE_FILE_FAILED = "创建存储文件失败"; 41 | 42 | //BarChart中用到的常量 43 | //设置要显示的柱状图的数量 44 | public final static int BAR_NUM = 16; 45 | //设置坐标系刻度线的数量 46 | public final static int LINE_NUM = 4; 47 | //设置最大SNR值 48 | public final static int MAX_SNR = 60; 49 | 50 | //SignalScaleBar用到的常量 51 | //设置将整个布局分成6份,柱状图画到2、3份中,字体 写到4、5份中 52 | public final static int SCALE_NUM = 5; 53 | //设置柱状图总共有几份 54 | public final static int SCALE_BAR_NUM = 10; 55 | //设置字体从mBarBottom下第几份开始 56 | public final static int FONT_START = 1; 57 | 58 | //LocationAdapter用到的常量 59 | public static final String GNSS_DATA_UNKNOWN = "N/A"; 60 | public static final String GNSS_DATA_ZERO = "0"; 61 | public static final String FIX_BEGIN = "正在定位"; 62 | public static final String FIX_SUCCEED = "已定位"; 63 | public static final String FIX_STOP = "未定位"; 64 | 65 | //SettingActivity中用到的常量 66 | public final static String SETTING_DATE_FORMAT = "Date_Format"; 67 | public final static String SETTING_TIME_FORMAT = "Time_Format"; 68 | public final static String SETTING_LONGITUDE_FORMAT = "Longitude_Format"; 69 | public final static String SETTING_ACCURACY_FORMAT = "Accuracy_Format"; 70 | public final static String SETTING_ALTITUDE_FORMAT = "Altitude_Format"; 71 | public final static String SETTING_SPEED_FORMAT = "Speed_Format"; 72 | public final static String SETTING_BEARING_FORMAT = "Bearing_Format"; 73 | public final static String SETTING_DEFAULT_FORMAT = "Default_Format"; 74 | 75 | //FileSelectView中用到的常量 76 | public final static String FILE_ROOT = "/"; 77 | public final static String FILE_PARENT = ".."; 78 | public final static String FILE_FOLDER = "."; 79 | public final static String FILE_BMP = "bmp"; 80 | public final static String FILE_DOC = "doc"; 81 | public final static String FILE_JPG = "jpg"; 82 | public final static String FILE_MP3 = "mp3"; 83 | public final static String FILE_MP4 = "mp4"; 84 | public final static String FILE_PPT = "ppt"; 85 | public final static String FILE_TXT = "txt"; 86 | public final static String FILE_WAV = "wav"; 87 | public final static String FILE_ZIP = "zip"; 88 | public final static String FILE_3GP = "3gp"; 89 | public final static String FILE_CAB = "cab"; 90 | public final static String FILE_TIF = "tif"; 91 | public final static String FILE_SWF = "swf"; 92 | public final static String FILE_CHM = "chm"; 93 | public final static String FILE_APK = "apk"; 94 | public final static String FILE_UNKNOWN = "unknown"; 95 | public final static String ACCESS_ERROR = "没有获取访问文件权限"; 96 | 97 | //MIME类型 98 | public final static String[][] MIME_MapTable={ 99 | //{后缀名, MIME类型} 100 | {".3gp", "video/3gpp"}, 101 | {".apk", "application/vnd.android.package-archive"}, 102 | {".asf", "video/x-ms-asf"}, 103 | {".avi", "video/x-msvideo"}, 104 | {".bin", "application/octet-stream"}, 105 | {".bmp", "image/bmp"}, 106 | {".c", "text/plain"}, 107 | {".class", "application/octet-stream"}, 108 | {".conf", "text/plain"}, 109 | {".cpp", "text/plain"}, 110 | {".doc", "application/msword"}, 111 | {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, 112 | {".xls", "application/vnd.ms-excel"}, 113 | {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, 114 | {".exe", "application/octet-stream"}, 115 | {".gif", "image/gif"}, 116 | {".gtar", "application/x-gtar"}, 117 | {".gz", "application/x-gzip"}, 118 | {".h", "text/plain"}, 119 | {".htm", "text/html"}, 120 | {".html", "text/html"}, 121 | {".jar", "application/java-archive"}, 122 | {".java", "text/plain"}, 123 | {".jpeg", "image/jpeg"}, 124 | {".jpg", "image/jpeg"}, 125 | {".js", "application/x-javascript"}, 126 | {".log", "text/plain"}, 127 | {".m3u", "audio/x-mpegurl"}, 128 | {".m4a", "audio/mp4a-latm"}, 129 | {".m4b", "audio/mp4a-latm"}, 130 | {".m4p", "audio/mp4a-latm"}, 131 | {".m4u", "video/vnd.mpegurl"}, 132 | {".m4v", "video/x-m4v"}, 133 | {".mov", "video/quicktime"}, 134 | {".mp2", "audio/x-mpeg"}, 135 | {".mp3", "audio/x-mpeg"}, 136 | {".mp4", "video/mp4"}, 137 | {".mpc", "application/vnd.mpohun.certificate"}, 138 | {".mpe", "video/mpeg"}, 139 | {".mpeg", "video/mpeg"}, 140 | {".mpg", "video/mpeg"}, 141 | {".mpg4", "video/mp4"}, 142 | {".mpga", "audio/mpeg"}, 143 | {".msg", "application/vnd.ms-outlook"}, 144 | {".ogg", "audio/ogg"}, 145 | {".pdf", "application/pdf"}, 146 | {".png", "image/png"}, 147 | {".pps", "application/vnd.ms-powerpoint"}, 148 | {".ppt", "application/vnd.ms-powerpoint"}, 149 | {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, 150 | {".prop", "text/plain"}, 151 | {".rc", "text/plain"}, 152 | {".rmvb", "audio/x-pn-realaudio"}, 153 | {".rtf", "application/rtf"}, 154 | {".sh", "text/plain"}, 155 | {".tar", "application/x-tar"}, 156 | {".tgz", "application/x-compressed"}, 157 | {".txt", "text/plain"}, 158 | {".wav", "audio/x-wav"}, 159 | {".wma", "audio/x-ms-wma"}, 160 | {".wmv", "audio/x-ms-wmv"}, 161 | {".wps", "application/vnd.ms-works"}, 162 | {".xml", "text/plain"}, 163 | {".z", "application/x-compress"}, 164 | {".zip", "application/x-zip-compressed"}, 165 | {"", "*/*"} 166 | }; 167 | 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/file/FileSelectView.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.file; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Locale; 8 | import java.util.Map; 9 | 10 | import com.tonker.gnss.R; 11 | import com.tonker.gnss.constant.Constant; 12 | 13 | import android.content.Context; 14 | import android.content.Intent; 15 | import android.net.Uri; 16 | import android.view.View; 17 | import android.widget.AdapterView; 18 | import android.widget.ListView; 19 | import android.widget.SimpleAdapter; 20 | import android.widget.Toast; 21 | import android.widget.AdapterView.OnItemClickListener; 22 | 23 | /** 24 | * 这一个类用来创建ListView列表,显示系统的文件夹和文件 25 | * 26 | * @author newtonker 27 | * @date 2014-07-01 28 | */ 29 | public class FileSelectView extends ListView implements OnItemClickListener 30 | { 31 | //获取当前路径 32 | private String path; 33 | 34 | //设置相应文件对应的图标,获取相应路径下的所有文件并添加到列表中 35 | private Map mImageMap; 36 | private File[] files; 37 | private List> list; 38 | 39 | // 回调接口,当其他应用程序打开文件时,回调这一接口是对话框消失 40 | private OpenFileDialogCallback mOpenFileDialogCallback; 41 | 42 | //constructor 43 | public FileSelectView(Context context) 44 | { 45 | super(context); 46 | } 47 | 48 | public FileSelectView(Context context, String path, OpenFileDialogCallback openFileDialogCallback) 49 | { 50 | super(context); 51 | 52 | this.path = path; 53 | this.mOpenFileDialogCallback = openFileDialogCallback; 54 | this.setOnItemClickListener(this); 55 | 56 | //创建可识别的文件与图标映射 57 | mImageMap = new HashMap(); 58 | mImageMap.put(Constant.FILE_ROOT, R.drawable.filedialog_root); 59 | mImageMap.put(Constant.FILE_PARENT, R.drawable.filedialog_folder_up); 60 | mImageMap.put(Constant.FILE_FOLDER, R.drawable.filedialog_folder); 61 | mImageMap.put(Constant.FILE_BMP, R.drawable.filedialog_bmp); 62 | mImageMap.put(Constant.FILE_DOC, R.drawable.filedialog_doc); 63 | mImageMap.put(Constant.FILE_JPG, R.drawable.filedialog_jpg); 64 | mImageMap.put(Constant.FILE_MP3, R.drawable.filedialog_mp3); 65 | mImageMap.put(Constant.FILE_MP4, R.drawable.filedialog_mp4); 66 | mImageMap.put(Constant.FILE_PPT, R.drawable.filedialog_ppt); 67 | mImageMap.put(Constant.FILE_TXT, R.drawable.filedialog_txt); 68 | mImageMap.put(Constant.FILE_WAV, R.drawable.filedialog_wav); 69 | mImageMap.put(Constant.FILE_ZIP, R.drawable.filedialog_zip); 70 | mImageMap.put(Constant.FILE_3GP, R.drawable.filedialog_3gp); 71 | mImageMap.put(Constant.FILE_CAB, R.drawable.filedialog_cab); 72 | mImageMap.put(Constant.FILE_TIF, R.drawable.filedialog_tif); 73 | mImageMap.put(Constant.FILE_SWF, R.drawable.filedialog_swf); 74 | mImageMap.put(Constant.FILE_CHM, R.drawable.filedialog_chm); 75 | mImageMap.put(Constant.FILE_APK, R.drawable.filedialog_apk); 76 | //无法识别的后缀时 77 | mImageMap.put(Constant.FILE_UNKNOWN, R.drawable.filedialog_unknown); 78 | refreshFileList(); 79 | } 80 | 81 | /** 82 | * 获取文件的后缀 83 | * 84 | * @param filename 85 | * @return 86 | */ 87 | private String getSuffix(String filename) 88 | { 89 | int index = filename.lastIndexOf("."); 90 | if (index < 0) 91 | { 92 | return ""; 93 | } 94 | else 95 | { 96 | return filename.substring(index + 1).toLowerCase(Locale.getDefault()); 97 | } 98 | } 99 | 100 | /** 101 | * 获取后缀所对应的图标 102 | * 103 | * @param s 104 | * @return 105 | */ 106 | private int getImageId(String s) 107 | { 108 | if (null == mImageMap) 109 | { 110 | return 0; 111 | } 112 | else if (mImageMap.containsKey(s)) 113 | { 114 | return mImageMap.get(s); 115 | } 116 | else 117 | { 118 | return mImageMap.get(Constant.FILE_UNKNOWN); 119 | } 120 | } 121 | 122 | /** 123 | * 每点击一次刷新列表 124 | */ 125 | private void refreshFileList() 126 | { 127 | try 128 | { 129 | files = new File(path).listFiles(); 130 | } 131 | catch (Exception e) 132 | { 133 | e.printStackTrace(); 134 | } 135 | if (null == files) 136 | { 137 | Toast.makeText(getContext(), Constant.ACCESS_ERROR, Toast.LENGTH_SHORT).show(); 138 | return; 139 | } 140 | if (null == list) 141 | { 142 | list = new ArrayList>(files.length); 143 | } 144 | else 145 | { 146 | list.clear(); 147 | } 148 | 149 | //创建文件夹列表和文件列表,保证文件夹优先显示 150 | ArrayList> folderList = new ArrayList>(); 151 | ArrayList> fileList = new ArrayList>(); 152 | 153 | Map tempMap; 154 | 155 | if (!path.equals(Constant.FILE_ROOT)) 156 | { 157 | //添加根目录和返回上一层目录 158 | tempMap = new HashMap(); 159 | tempMap.put("name", Constant.FILE_ROOT); 160 | tempMap.put("path", Constant.FILE_ROOT); 161 | tempMap.put("img", getImageId(Constant.FILE_ROOT)); 162 | list.add(tempMap); 163 | 164 | tempMap = new HashMap(); 165 | tempMap.put("name", Constant.FILE_PARENT); 166 | tempMap.put("path", path); 167 | tempMap.put("img", getImageId(Constant.FILE_PARENT)); 168 | list.add(tempMap); 169 | } 170 | for (File file : files) 171 | { 172 | if (file.isDirectory() && file.listFiles() != null) 173 | { 174 | tempMap = new HashMap(); 175 | tempMap.put("name", file.getName()); 176 | tempMap.put("path", file.getPath()); 177 | tempMap.put("img", getImageId(Constant.FILE_FOLDER)); 178 | folderList.add(tempMap); 179 | } 180 | else if (file.isFile()) 181 | { 182 | //获取后缀 183 | String suffix = getSuffix(file.getName()); 184 | if (suffix.length() > 0) 185 | { 186 | tempMap = new HashMap(); 187 | tempMap.put("name", file.getName()); 188 | tempMap.put("path", file.getPath()); 189 | tempMap.put("img", getImageId(suffix)); 190 | fileList.add(tempMap); 191 | } 192 | } 193 | } 194 | list.addAll(folderList); 195 | list.addAll(fileList); 196 | 197 | SimpleAdapter mSimpleAdapter = new SimpleAdapter(getContext(), list, R.layout.filedialog_item, new String[]{"img", "name", "path"}, new int[]{R.id.filedialog_item_img, R.id.filedialog_item_name, R.id.filedialog_item_path}); 198 | this.setAdapter(mSimpleAdapter); 199 | } 200 | 201 | /** 202 | * 当Item点击时的侦听 203 | */ 204 | @Override 205 | public void onItemClick(AdapterView parent, View view, int position, long id) 206 | { 207 | //条目选择 208 | String mFilePath = (String) list.get(position).get("path"); 209 | String mFileName = (String) list.get(position).get("name"); 210 | //获取当前路径所表示的文件 211 | File tempFile = new File(mFilePath); 212 | 213 | //如果选择的是根目录或返回上层目录 214 | if (mFileName.equals(Constant.FILE_ROOT) || mFileName.equals(Constant.FILE_PARENT)) 215 | { 216 | String tempParent = tempFile.getAbsoluteFile().getParent(); 217 | if (null != tempParent) 218 | { 219 | path = tempParent; 220 | } 221 | else 222 | { 223 | path = Constant.FILE_ROOT; 224 | } 225 | } 226 | else 227 | { 228 | if (tempFile.isFile()) 229 | { 230 | //如果是文件则进行相应操作 231 | openFile(tempFile, view); 232 | //回调接口,在文件打开后,对话框消失 233 | if (null != mOpenFileDialogCallback) 234 | { 235 | mOpenFileDialogCallback.dismissDialog(); 236 | } 237 | } 238 | else if (tempFile.isDirectory()) 239 | { 240 | path = mFilePath; 241 | } 242 | } 243 | this.refreshFileList(); 244 | } 245 | 246 | 247 | /** 248 | * 打开文件 249 | * @param file 250 | * @param view 251 | */ 252 | private void openFile(File file, View view) 253 | { 254 | Intent intent = new Intent(); 255 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 256 | //设置intent的Action属性 257 | intent.setAction(Intent.ACTION_VIEW); 258 | //获取文件file的MIME类型 259 | String type = getMIMEType(file); 260 | //设置intent的data和Type属性。 261 | intent.setDataAndType(/*uri*/Uri.fromFile(file), type); 262 | //跳转 263 | view.getContext().startActivity(intent); 264 | } 265 | 266 | /** 267 | * 根据文件后缀名获得对应的MIME类型。 268 | * 269 | * @param file 270 | */ 271 | private String getMIMEType(File file) 272 | { 273 | String type = "*/*"; 274 | String fName = file.getName(); 275 | // 获取文件的后缀名 276 | String end = getSuffix(fName); 277 | if (end.equals("")) 278 | { 279 | return type; 280 | } 281 | //在MIME和文件类型的匹配表中找到对应的MIME类型。 282 | for (int i = 0; i < Constant.MIME_MapTable.length; i++) 283 | { 284 | //MIME_MapTable??在这里你一定有疑问,这个MIME_MapTable是什么 285 | if (end.equalsIgnoreCase(Constant.MIME_MapTable[i][0])) 286 | { 287 | type = Constant.MIME_MapTable[i][1]; 288 | } 289 | } 290 | return type; 291 | } 292 | 293 | 294 | } 295 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/file/NmeaConsumer.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.file; 2 | 3 | /** 4 | * 消费者类,用于往文件中存储数据 5 | * @author newtonker 6 | * @date 2014-06-30 7 | */ 8 | public class NmeaConsumer extends Thread 9 | { 10 | private NmeaStorage mNmeaStorage; 11 | 12 | public NmeaConsumer(NmeaStorage nmeaStorage) 13 | { 14 | this.mNmeaStorage = nmeaStorage; 15 | } 16 | 17 | public void run() 18 | { 19 | consume(); 20 | } 21 | 22 | public void consume() 23 | { 24 | mNmeaStorage.consume(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/file/NmeaProducer.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.file; 2 | 3 | /** 4 | * 生产者类,用于将产生的数据保存到数据仓库中 5 | * @author newtonker 6 | * @date 2014-06-30 7 | */ 8 | public class NmeaProducer extends Thread 9 | { 10 | private NmeaStorage mNmeaStorage; 11 | private String mNmea; 12 | 13 | public NmeaProducer(NmeaStorage nmeaStorage) 14 | { 15 | this.mNmeaStorage = nmeaStorage; 16 | } 17 | 18 | public void run() 19 | { 20 | produce(mNmea); 21 | } 22 | 23 | public void produce(String string) 24 | { 25 | mNmeaStorage.produce(string); 26 | } 27 | 28 | public void setmNmea(String mNmea) 29 | { 30 | this.mNmea = mNmea; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/file/NmeaStorage.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.file; 2 | 3 | import java.io.FileWriter; 4 | import java.io.IOException; 5 | 6 | /** 7 | * 这一类用来存储获得的Nmea数据,有同步方法 8 | * @author newtonker 9 | * @date 2014-06-30 10 | */ 11 | public class NmeaStorage 12 | { 13 | //用于存储获取的数据 14 | private final StringBuffer mNmeaBuffer = new StringBuffer(); 15 | //文件输出字符流 16 | private FileWriter mFileWriter; 17 | 18 | /** 19 | * 生产方法 20 | * @param nmea 21 | */ 22 | public void produce(String nmea) 23 | { 24 | synchronized(mNmeaBuffer) 25 | { 26 | try 27 | { 28 | while (0 != mNmeaBuffer.length()) 29 | { 30 | mNmeaBuffer.wait(); 31 | } 32 | if(null != nmea) 33 | { 34 | mNmeaBuffer.append(nmea); 35 | } 36 | mNmeaBuffer.notify(); 37 | } 38 | catch (InterruptedException e) 39 | { 40 | e.printStackTrace(); 41 | } 42 | } 43 | } 44 | 45 | /** 46 | * 消费方法 47 | */ 48 | public void consume() 49 | { 50 | synchronized(mNmeaBuffer) 51 | { 52 | try 53 | { 54 | while(0 == mNmeaBuffer.length()) 55 | { 56 | mNmeaBuffer.wait(); 57 | } 58 | if(null != mFileWriter) 59 | { 60 | mFileWriter.write(mNmeaBuffer.toString()); 61 | mNmeaBuffer.delete(0, mNmeaBuffer.length()-1); 62 | } 63 | mNmeaBuffer.notify(); 64 | } 65 | catch(InterruptedException e) 66 | { 67 | e.printStackTrace(); 68 | } 69 | catch(IOException e) 70 | { 71 | e.printStackTrace(); 72 | } 73 | } 74 | } 75 | 76 | /** 77 | * 设置当前类的文件字符输出流 78 | * @param mFileWriter 79 | */ 80 | public void setmFileWriter(FileWriter mFileWriter) 81 | { 82 | this.mFileWriter = mFileWriter; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/file/OpenFileDialog.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.file; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.widget.Toast; 6 | 7 | /** 8 | * 这一个类用来创建打开文件时的对话框 9 | * 10 | * @author newtonker 11 | * @date 2014-07-01 12 | */ 13 | public class OpenFileDialog 14 | { 15 | private AlertDialog mOpenFileDialog; 16 | 17 | public OpenFileDialog(Context context, String folderPath) 18 | { 19 | if (null == folderPath) 20 | { 21 | Toast.makeText(context, "访问的文件夹不存在", Toast.LENGTH_SHORT).show(); 22 | } 23 | else 24 | { 25 | mOpenFileDialog = new AlertDialog.Builder(context).setView(new FileSelectView(context, folderPath, mOpenFileDialogCallback)).setTitle("打开文件夹").create(); 26 | mOpenFileDialog.show(); 27 | } 28 | } 29 | 30 | private OpenFileDialogCallback mOpenFileDialogCallback = new OpenFileDialogCallback() 31 | { 32 | @Override 33 | public void dismissDialog() 34 | { 35 | if (null != mOpenFileDialog) 36 | { 37 | mOpenFileDialog.dismiss(); 38 | } 39 | } 40 | }; 41 | 42 | public OpenFileDialogCallback getmOpenFileDialogCallback() 43 | { 44 | return mOpenFileDialogCallback; 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/file/OpenFileDialogCallback.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.file; 2 | 3 | /** 4 | * 定义一个回调函数,当文件被单击后打开时,自动关闭对话框 5 | * @author newtonker 6 | * @date 2014-07-01 7 | */ 8 | public interface OpenFileDialogCallback 9 | { 10 | void dismissDialog(); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/FragmentTabAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import android.view.View; 4 | import android.widget.ImageView; 5 | import android.widget.RadioGroup; 6 | import android.widget.Toast; 7 | import android.view.View.OnClickListener; 8 | import android.support.v4.app.Fragment; 9 | import android.support.v4.app.FragmentManager; 10 | import android.support.v4.app.FragmentTransaction; 11 | 12 | import com.tonker.gnss.R; 13 | 14 | /** 15 | * 创建一个类,实现底部单选按钮切换和Fragment的匹配 16 | * @author newtonker 17 | * @date 2014-06-10 18 | */ 19 | public class FragmentTabAdapter implements RadioGroup.OnCheckedChangeListener 20 | { 21 | //FragmentManager、FragmentTransaction及五个Fragment 22 | private FragmentManager mFragmentManager; 23 | private FragmentTransaction mFragmentTransaction; 24 | private SignalFragment mSignalFragment; 25 | private OrientationFragment mOrientationFragment; 26 | private TimeFragment mTimeFragment; 27 | private MessageFragment mMessageFragment; 28 | //用于记录当前正在显示的Fragment 29 | private Fragment mCurrentFragment; 30 | //用于切换Fragment 31 | private RadioGroup mRadioGroup; 32 | //Fragment标志位,判断各个Fragment是否已经建立 33 | private boolean isSignal; 34 | private boolean isOrientation; 35 | private boolean isTime; 36 | private boolean isMessage; 37 | 38 | public FragmentTabAdapter(ImageView leftImageView, ImageView rightImageView, FragmentManager fragmentManager, 39 | SignalFragment signalFragment,OrientationFragment orientationFragment, TimeFragment timeFragment, 40 | MessageFragment messageFragment, RadioGroup group) 41 | { 42 | this.mFragmentManager = fragmentManager; 43 | this.mSignalFragment = signalFragment; 44 | this.mOrientationFragment = orientationFragment; 45 | this.mTimeFragment = timeFragment; 46 | this.mMessageFragment = messageFragment; 47 | this.mRadioGroup = group; 48 | 49 | //对后退键和下一页键设置侦听 50 | leftImageView.setOnClickListener(mButtonOnClickListener); 51 | rightImageView.setOnClickListener(mButtonOnClickListener); 52 | //对单选按钮组侦听 53 | mRadioGroup.setOnCheckedChangeListener(this); 54 | //显示第一页 55 | mFragmentTransaction = mFragmentManager.beginTransaction(); 56 | mFragmentTransaction.add(R.id.content, mSignalFragment); 57 | //设置第一页标识位 58 | isSignal = true; 59 | mCurrentFragment = mSignalFragment; 60 | mFragmentTransaction.commit(); 61 | } 62 | 63 | @Override 64 | public void onCheckedChanged(RadioGroup group, int checkedId) 65 | { 66 | //获取当前Fragment 67 | if(null != mCurrentFragment) 68 | { 69 | mFragmentTransaction = mFragmentManager.beginTransaction(); 70 | mFragmentTransaction.hide(mCurrentFragment); 71 | } 72 | switch(checkedId) 73 | { 74 | case R.id.button_signal: 75 | if(isSignal) 76 | { 77 | mFragmentTransaction.show(mSignalFragment); 78 | } 79 | else 80 | { 81 | isSignal = true; 82 | mFragmentTransaction.add(R.id.content, mSignalFragment); 83 | } 84 | mCurrentFragment = mSignalFragment; 85 | break; 86 | case R.id.button_orientation: 87 | if(isOrientation) 88 | { 89 | mFragmentTransaction.show(mOrientationFragment); 90 | } 91 | else 92 | { 93 | isOrientation = true; 94 | mFragmentTransaction.add(R.id.content, mOrientationFragment); 95 | } 96 | mCurrentFragment = mOrientationFragment; 97 | break; 98 | case R.id.button_time: 99 | if(isTime) 100 | { 101 | mFragmentTransaction.show(mTimeFragment); 102 | } 103 | else 104 | { 105 | isTime = true; 106 | mFragmentTransaction.add(R.id.content, mTimeFragment); 107 | } 108 | mCurrentFragment = mTimeFragment; 109 | break; 110 | case R.id.button_message: 111 | if(isMessage) 112 | { 113 | mFragmentTransaction.show(mMessageFragment); 114 | } 115 | else 116 | { 117 | isMessage = true; 118 | mFragmentTransaction.add(R.id.content, mMessageFragment); 119 | } 120 | mCurrentFragment = mMessageFragment; 121 | break; 122 | } 123 | mFragmentTransaction.commit(); 124 | mFragmentManager.executePendingTransactions(); 125 | } 126 | 127 | //对标题栏左右按钮设置侦听 128 | private OnClickListener mButtonOnClickListener = new OnClickListener() 129 | { 130 | @Override 131 | public void onClick(View v) 132 | { 133 | mFragmentTransaction = mFragmentManager.beginTransaction(); 134 | switch(v.getId()) 135 | { 136 | case R.id.title_back_btn: 137 | if(null == mCurrentFragment) 138 | { 139 | return; 140 | } 141 | if(mSignalFragment == mCurrentFragment) 142 | { 143 | Toast.makeText(v.getContext(), "当前已是第一页", Toast.LENGTH_SHORT).show(); 144 | } 145 | else 146 | { 147 | mFragmentTransaction.hide(mCurrentFragment); 148 | if(mOrientationFragment == mCurrentFragment) 149 | { 150 | mRadioGroup.check(R.id.button_signal); 151 | } 152 | else if(mTimeFragment == mCurrentFragment) 153 | { 154 | mRadioGroup.check(R.id.button_orientation); 155 | } 156 | else if(mMessageFragment == mCurrentFragment) 157 | { 158 | mRadioGroup.check(R.id.button_time); 159 | } 160 | } 161 | break; 162 | case R.id.title_next_btn: 163 | if(null == mCurrentFragment) 164 | { 165 | return; 166 | } 167 | if(mMessageFragment == mCurrentFragment) 168 | { 169 | Toast.makeText(v.getContext(), "当前已是最后一页", Toast.LENGTH_SHORT).show(); 170 | } 171 | else 172 | { 173 | mFragmentTransaction.hide(mCurrentFragment); 174 | if(mSignalFragment == mCurrentFragment) 175 | { 176 | mRadioGroup.check(R.id.button_orientation); 177 | } 178 | else if(mOrientationFragment == mCurrentFragment) 179 | { 180 | mRadioGroup.check(R.id.button_time); 181 | } 182 | else if(mTimeFragment == mCurrentFragment) 183 | { 184 | mRadioGroup.check(R.id.button_message); 185 | } 186 | } 187 | break; 188 | default: 189 | break; 190 | } 191 | } 192 | }; 193 | } 194 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/MessageCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | /** 4 | * MessageFragment用于回调的接口 5 | * @author newtonker 6 | * @date 2014-06-17 7 | */ 8 | public interface MessageCallbacks 9 | { 10 | /** 11 | * 更新导航电文等信息 12 | * @param timestamp 13 | * @param nmea 14 | * @param isGnssEnabled 15 | */ 16 | void updateMessageViewInfo(long timestamp, String nmea, boolean isGnssEnabled); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/MessageFragment.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import java.io.File; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.sql.Timestamp; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.Locale; 10 | 11 | import com.tonker.gnss.R; 12 | import com.tonker.gnss.constant.Constant; 13 | import com.tonker.gnss.file.*; 14 | 15 | import android.support.v4.app.Fragment; 16 | import android.content.Context; 17 | import android.os.Bundle; 18 | import android.os.Environment; 19 | import android.view.LayoutInflater; 20 | import android.view.View; 21 | import android.view.ViewGroup; 22 | import android.widget.Button; 23 | import android.widget.CheckBox; 24 | import android.widget.CompoundButton; 25 | import android.widget.ScrollView; 26 | import android.widget.TextView; 27 | import android.widget.Toast; 28 | 29 | /** 30 | * 这个Fragment实现了第四个界面(导航电文)的显示 31 | * 32 | * @author newtonker 33 | * @date 2014-06-17 34 | */ 35 | public class MessageFragment extends Fragment 36 | { 37 | //设置标志位,判断MessageFragment的onCreateView是否已经创建,updateMessageViewInfo时用 38 | private boolean isInit = false; 39 | //设置复选框的标志位 40 | private boolean isGpsEnabled = true; 41 | private boolean isBdsEnabled = true; 42 | private boolean isGlonassEnabled = true; 43 | private boolean isGalileoEnabled = true; 44 | //设置暂停、保存标志位 45 | private boolean isPauseEnabled = false; 46 | private boolean isSaveEnabled = false; 47 | 48 | //容器中的部件 49 | private Button mPauseButton; 50 | private Button mSaveButton; 51 | private ScrollView mScrollView; 52 | private TextView mMessageTextView; 53 | 54 | //用于将时间戳转换成相应格式的时间 55 | private SimpleDateFormat mNmeaSimpleDateFormat; 56 | private Timestamp mLocalTimestamp; 57 | 58 | //显示协议时需要判断时间戳,一秒钟显示一次 59 | private String mNmeaTime; 60 | private String mNmea; 61 | private StringBuilder mNmeaBuilder; 62 | private int mLineCount; 63 | 64 | //NMEA0183保存时需要的保存路径和文件 65 | private String mTargetDirStr; 66 | private File mTargetDir; 67 | private FileWriter mNmeaFileWriter; 68 | 69 | 70 | //对文件操作时使用同步锁,创建文件、关闭文件、读写文件时都需要同步锁定; 71 | private Object mLock = new Object(); 72 | 73 | @Override 74 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 75 | { 76 | View view = inflater.inflate(R.layout.tab_d, container, false); 77 | initView(view); 78 | 79 | //设置时间戳格式 80 | mNmeaSimpleDateFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); 81 | mLocalTimestamp = new Timestamp(0); 82 | //设置用于存储协议的StringBuilder 83 | mNmeaBuilder = new StringBuilder(Constant.STRING_BUILDER_CAPATICY); 84 | 85 | initMessageView(); 86 | isInit = true; 87 | return view; 88 | } 89 | 90 | /** 91 | * 初始化界面 92 | * 93 | * @param view 94 | */ 95 | private void initView(View view) 96 | { 97 | //设置标题题目 98 | TextView mTitleText = (TextView) view.findViewById(R.id.title_name_content); 99 | mTitleText.setText(R.string.message); 100 | 101 | //获取复选框按钮 102 | CheckBox mGpsCheckBox = (CheckBox) view.findViewById(R.id.message_gps); 103 | CheckBox mBdsCheckBox = (CheckBox) view.findViewById(R.id.message_bds); 104 | CheckBox mGlonassCheckBox = (CheckBox) view.findViewById(R.id.message_glonass); 105 | CheckBox mGalileoCheckBox = (CheckBox) view.findViewById(R.id.message_galileo); 106 | //对复选框按钮设置侦听 107 | mGpsCheckBox.setOnCheckedChangeListener(mCheckedChangeListener); 108 | mBdsCheckBox.setOnCheckedChangeListener(mCheckedChangeListener); 109 | mGlonassCheckBox.setOnCheckedChangeListener(mCheckedChangeListener); 110 | mGalileoCheckBox.setOnCheckedChangeListener(mCheckedChangeListener); 111 | //获取暂停和保存按钮 112 | mPauseButton = (Button) view.findViewById(R.id.message_pause); 113 | mPauseButton.setText("暂停"); 114 | Button mClearButton = (Button) view.findViewById(R.id.message_clear); 115 | mSaveButton = (Button) view.findViewById(R.id.message_save); 116 | mSaveButton.setText("保存"); 117 | Button mOpenButton = (Button) view.findViewById(R.id.message_open); 118 | //对暂停和保存按钮设置侦听 119 | mPauseButton.setOnClickListener(mClickListener); 120 | mOpenButton.setOnClickListener(mClickListener); 121 | mClearButton.setOnClickListener(mClickListener); 122 | mSaveButton.setOnClickListener(mClickListener); 123 | //获取滑动View及文本显示部件 124 | mScrollView = (ScrollView) view.findViewById(R.id.message_scroll_view); 125 | mMessageTextView = (TextView) view.findViewById(R.id.message_info); 126 | //设置协议文本接收的最大行数 127 | mMessageTextView.setMaxLines(Constant.MAX_LINE); 128 | } 129 | 130 | //增加对四个复选框的侦听 131 | CompoundButton.OnCheckedChangeListener mCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() 132 | { 133 | @Override 134 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 135 | { 136 | //判断是否被选中 137 | if (isChecked) 138 | { 139 | switch (buttonView.getId()) 140 | { 141 | case R.id.message_gps: 142 | isGpsEnabled = true; 143 | break; 144 | case R.id.message_bds: 145 | isBdsEnabled = true; 146 | break; 147 | case R.id.message_glonass: 148 | isGlonassEnabled = true; 149 | break; 150 | case R.id.message_galileo: 151 | isGalileoEnabled = true; 152 | break; 153 | default: 154 | break; 155 | } 156 | } 157 | else 158 | { 159 | switch (buttonView.getId()) 160 | { 161 | case R.id.message_gps: 162 | isGpsEnabled = false; 163 | break; 164 | case R.id.message_bds: 165 | isBdsEnabled = false; 166 | break; 167 | case R.id.message_glonass: 168 | isGlonassEnabled = false; 169 | break; 170 | case R.id.message_galileo: 171 | isGalileoEnabled = false; 172 | break; 173 | default: 174 | break; 175 | } 176 | } 177 | } 178 | }; 179 | 180 | //增加对三个按钮的侦听 181 | View.OnClickListener mClickListener = new View.OnClickListener() 182 | { 183 | @Override 184 | public void onClick(View v) 185 | { 186 | switch (v.getId()) 187 | { 188 | case R.id.message_pause: 189 | isPauseEnabled = !isPauseEnabled; 190 | if (isPauseEnabled) 191 | { 192 | mPauseButton.setText(Constant.MESSAGE_CONTINUE); 193 | } 194 | else 195 | { 196 | mPauseButton.setText(Constant.MESSAGE_PAUSE); 197 | } 198 | break; 199 | case R.id.message_clear: 200 | mMessageTextView.setText(""); 201 | mNmeaBuilder.delete(0, mNmeaBuilder.capacity()); 202 | mLineCount = 0; 203 | break; 204 | case R.id.message_save: 205 | isSaveEnabled = !isSaveEnabled; 206 | if (isSaveEnabled) 207 | { 208 | //首先判断是否创建成功,如果不成功则仍然保持保存按钮状态 209 | if (null == createNmeaDir(v.getContext())) 210 | { 211 | isSaveEnabled = !isSaveEnabled; 212 | mSaveButton.setText(Constant.MESSAGE_SAVE); 213 | } 214 | else 215 | { 216 | mSaveButton.setText(Constant.MESSAGE_CANCEL_SAVE); 217 | } 218 | } 219 | else 220 | { 221 | mSaveButton.setText(Constant.MESSAGE_SAVE); 222 | } 223 | createNmeaFile(isSaveEnabled, v.getContext()); 224 | break; 225 | case R.id.message_open: 226 | String mFolderPath = createNmeaDir(v.getContext()); 227 | if (null == mFolderPath) 228 | { 229 | return; 230 | } 231 | showDialog(getActivity(), mFolderPath); 232 | break; 233 | default: 234 | break; 235 | } 236 | } 237 | }; 238 | 239 | /** 240 | * 当单击打开按钮时,显示对话框 241 | * 242 | * @param context 243 | * @param s 244 | */ 245 | public void showDialog(Context context, String s) 246 | { 247 | new OpenFileDialog(context, s); 248 | } 249 | 250 | /** 251 | * 创建待保存数据的文件夹 252 | * 253 | * @param context 254 | * @return 255 | */ 256 | private String createNmeaDir(Context context) 257 | { 258 | if (null != mTargetDirStr && null != mTargetDir && mTargetDir.exists()) 259 | { 260 | return mTargetDirStr; 261 | } 262 | try 263 | { 264 | // 如果手机插入了SD卡,而且应用程序具有访问SD卡的权限 265 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) 266 | { 267 | // 获取SD卡的目录 268 | File mSdCardDir = Environment.getExternalStorageDirectory(); 269 | mTargetDirStr = new StringBuilder().append(mSdCardDir.getCanonicalPath()).append(Constant.FILE_SAVE_DIR).toString(); 270 | } 271 | // 如果没有SD卡,或者不具有SD卡访问权限,则保存到手机内置的存储空间 272 | else 273 | { 274 | mTargetDirStr = new StringBuilder().append(context.getFilesDir()).append(Constant.FILE_SAVE_DIR).toString(); 275 | } 276 | mTargetDir = new File(mTargetDirStr); 277 | // 如果目标路径不存在则创建 278 | if (!mTargetDir.exists()) 279 | { 280 | if (!mTargetDir.mkdirs()) 281 | { 282 | showToast(context, Constant.CREATE_DIR_FAILED); 283 | return null; 284 | } 285 | } 286 | return mTargetDirStr; 287 | } 288 | catch (Exception e) 289 | { 290 | e.printStackTrace(); 291 | } 292 | return null; 293 | } 294 | 295 | /** 296 | * 创建待保存的NMEA0183协议文件,命名格式为当前日期及时间 297 | * 298 | * @param isSave 299 | * @param context 300 | */ 301 | private void createNmeaFile(boolean isSave, Context context) 302 | { 303 | if (isSave) 304 | { 305 | SimpleDateFormat mLocalSimpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault()); 306 | String mNmeaFileStr = String.format("%s.txt", mLocalSimpleDateFormat.format(new Date())); 307 | File mNmeaFile; 308 | try 309 | { 310 | synchronized (mLock) 311 | { 312 | mNmeaFile = new File(mTargetDirStr + mNmeaFileStr); 313 | if (!mNmeaFile.createNewFile()) 314 | { 315 | showToast(context, Constant.CREATE_FILE_FAILED); 316 | return; 317 | } 318 | } 319 | // 追加模式操作文件 320 | mNmeaFileWriter = new FileWriter(mNmeaFile, true); 321 | showToast(context, Constant.FILE_SAVE_START + mTargetDirStr + mNmeaFileStr); 322 | // 创建成功则返回,开始接收数据 323 | return; 324 | } 325 | catch (IOException e) 326 | { 327 | e.printStackTrace(); 328 | } 329 | } 330 | //如果停止保存 331 | try 332 | { 333 | synchronized (mLock) 334 | { 335 | if (null != mNmeaFileWriter) 336 | { 337 | mNmeaFileWriter.flush(); 338 | mNmeaFileWriter = null; 339 | showToast(context, Constant.FILE_SAVE_STOP); 340 | } 341 | } 342 | } 343 | catch (IOException e) 344 | { 345 | e.printStackTrace(); 346 | } 347 | } 348 | 349 | /** 350 | * 吐司提示相应操作 351 | * 352 | * @param context 353 | * @param string 354 | */ 355 | private void showToast(Context context, String string) 356 | { 357 | Toast.makeText(context, string, Toast.LENGTH_SHORT).show(); 358 | } 359 | 360 | /** 361 | * 输出符合筛选条件的NMEA0183协议 362 | * 363 | * @param timestamp 364 | * @param nmea 365 | */ 366 | private void updateNmeaView(long timestamp, String nmea) 367 | { 368 | if (null == nmea) 369 | { 370 | return; 371 | } 372 | mLocalTimestamp.setTime(timestamp); 373 | String mTimestamp = String.format("%s", mNmeaSimpleDateFormat.format(mLocalTimestamp)); 374 | String mNmea = String.format("%s %s", mTimestamp, nmea); 375 | 376 | //判断是否需要保存数据 377 | if (isSaveEnabled) 378 | { 379 | synchronized (mLock) 380 | { 381 | //初始化生产者消费者模式的相关类 382 | NmeaStorage mNmeaStorage = new NmeaStorage(); 383 | mNmeaStorage.setmFileWriter(mNmeaFileWriter); 384 | NmeaProducer mNmeaProducer = new NmeaProducer(mNmeaStorage); 385 | mNmeaProducer.setmNmea(mNmea); 386 | NmeaConsumer mNmeaConsumer = new NmeaConsumer(mNmeaStorage); 387 | mNmeaProducer.start(); 388 | mNmeaConsumer.start(); 389 | } 390 | } 391 | //判断是否暂停 392 | if (isPauseEnabled) 393 | { 394 | return; 395 | } 396 | //判断是否禁止显示某一类卫星 397 | if (!isGpsEnabled && 'P' == nmea.charAt(2) && 'G' == nmea.charAt(1) && '$' == nmea.charAt(0)) 398 | { 399 | return; 400 | } 401 | if (!isBdsEnabled && 'D' == nmea.charAt(2) && 'B' == nmea.charAt(1) && '$' == nmea.charAt(0)) 402 | { 403 | return; 404 | } 405 | if (!isGlonassEnabled && 'L' == nmea.charAt(2) && 'G' == nmea.charAt(1) && '$' == nmea.charAt(0)) 406 | { 407 | return; 408 | } 409 | if (!isGalileoEnabled && 'A' == nmea.charAt(2) && 'G' == nmea.charAt(1) && '$' == nmea.charAt(0)) 410 | { 411 | return; 412 | } 413 | //判断当前时间戳是否和之前时间戳相同 414 | if (!mTimestamp.equals(mNmeaTime)) 415 | { 416 | mNmeaTime = mTimestamp; 417 | mMessageTextView.setText(mNmeaBuilder.toString()); 418 | } 419 | mLineCount++; 420 | if (mLineCount > Constant.MAX_LINE) 421 | { 422 | mLineCount = Constant.MAX_LINE; 423 | mNmeaBuilder.delete(0, mNmeaBuilder.indexOf("*") + 5); 424 | } 425 | mNmeaBuilder.append(mNmea); 426 | //保证处于最底端,此处使用的是主UI线程 427 | mScrollView.post(new Runnable() 428 | { 429 | @Override 430 | public void run() 431 | { 432 | mScrollView.fullScroll(ScrollView.FOCUS_DOWN); 433 | } 434 | }); 435 | } 436 | 437 | //创建MessageCallbacks接口实例,用于回调 438 | private MessageCallbacks mMessageCallbacks = new MessageCallbacks() 439 | { 440 | @Override 441 | public void updateMessageViewInfo(long timestamp, String nmea, boolean isGnssEnabled) 442 | { 443 | if (isInit) 444 | { 445 | if (isGnssEnabled) 446 | { 447 | updateNmeaView(timestamp, nmea); 448 | } 449 | else 450 | { 451 | initMessageView(); 452 | } 453 | } 454 | } 455 | }; 456 | 457 | /** 458 | * 返回MessageFragment实例的MessageCallbacks方法 459 | * 460 | * @return 461 | */ 462 | public MessageCallbacks getMessageCallbacks() 463 | { 464 | return mMessageCallbacks; 465 | } 466 | 467 | /** 468 | * 初始化显示界面 469 | */ 470 | private void initMessageView() 471 | { 472 | mMessageTextView.setText(""); 473 | } 474 | 475 | /** 476 | * 获取文件输出字符流 477 | * 478 | * @return 479 | */ 480 | public FileWriter getmNmeaFileWriter() 481 | { 482 | return mNmeaFileWriter; 483 | } 484 | 485 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/OrientationCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import com.tonker.gnss.location.SatelliteAdapter; 4 | 5 | /** 6 | * OrientationFragment用于回调的接口 7 | * @author newtonker 8 | * @date 2014-06-17 9 | */ 10 | public interface OrientationCallbacks 11 | { 12 | /** 13 | * 当位置变化时调用此方法 14 | * @param isGnssEnabled GNSS开关是否可用 15 | */ 16 | void updateOrientationViewLocationInfo(boolean isGnssEnabled); 17 | 18 | /** 19 | * 更新可见卫星,已连接卫星,首次定位时长等信息 20 | * @param satelliteAdapter 存放可见卫星数,已连接卫星数,可见卫星方位,首次定位时长等信息 21 | * @param isGnssEnabled 检测GNSS是否可用,true:可用, false:不可用 22 | */ 23 | void updateOrientationViewInfo(SatelliteAdapter satelliteAdapter, boolean isGnssEnabled); 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/OrientationFragment.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import com.tonker.gnss.R; 4 | import com.tonker.gnss.constant.Constant; 5 | import com.tonker.gnss.graphics.*; 6 | import com.tonker.gnss.location.SatelliteAdapter; 7 | import android.support.v4.app.Fragment; 8 | import android.os.Bundle; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.ViewTreeObserver; 13 | import android.widget.LinearLayout; 14 | import android.widget.TextView; 15 | 16 | /** 17 | * 这个Fragment实现了第二个界面(卫星方位的显示) 18 | * @author newtonker 19 | * @date 2014-06-17 20 | */ 21 | public class OrientationFragment extends Fragment { 22 | 23 | //卫星方位容器宽高 24 | private int mScaleLayoutWidth; 25 | private int mScaleLayoutHeight; 26 | //卫星颜色容器宽高 27 | private int mSatelliteViewWidth; 28 | private int mSatelliteViewHeight; 29 | //设置标志位,判断OrientationFragment的onCreateView是否已经创建,updateOrientionView时用 30 | private boolean isInit = false; 31 | 32 | //可见卫星文本框、已连接卫星文本框等 33 | private TextView visible; 34 | private TextView connect; 35 | // private TextView fixTime; 36 | 37 | //获取卫星方位图布局 38 | private SatelliteView mSatelliteView; 39 | private SatelliteViewCallbacks mSatelliteViewCallbacks; 40 | 41 | //获取卫星颜色容器 42 | private SignalScaleBar mSignalScaleBar; 43 | private SignalScaleBarCallbacks mSignalScaleBarCallbacks; 44 | 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 47 | { 48 | View view = inflater.inflate(R.layout.tab_b, container, false); 49 | initView(view); 50 | initOrientationView(); 51 | isInit = true; 52 | return view; 53 | } 54 | 55 | /** 56 | * 初始化视图 57 | * @param view 58 | */ 59 | private void initView(View view) 60 | { 61 | //设置标题题目 62 | TextView mTitleText = (TextView) view.findViewById(R.id.title_name_content); 63 | mTitleText.setText(R.string.orientation); 64 | 65 | visible =(TextView) view.findViewById(R.id.bvisiable_num); 66 | // fixTime = (TextView) view.findViewById(R.id.connect_time); 67 | connect =(TextView) view.findViewById(R.id.bconnect_num); 68 | 69 | //对mSatelliteViewLayout设置侦听,获取宽和高 70 | LinearLayout mSatelliteViewLayout = (LinearLayout) view.findViewById(R.id.satellite_view_layout); 71 | SatelliteViewLayoutListener mSatelliteViewLayoutListener = new SatelliteViewLayoutListener(mSatelliteViewLayout); 72 | ViewTreeObserver mSatelliteObserver = mSatelliteViewLayout.getViewTreeObserver(); 73 | mSatelliteObserver.addOnPreDrawListener(mSatelliteViewLayoutListener); 74 | //获取SatelliteView实例 75 | mSatelliteView = (SatelliteView) view.findViewById(R.id.satellite_view); 76 | mSatelliteViewCallbacks = mSatelliteView.getmSatelliteViewCallbacks(); 77 | 78 | // 对mScaleObserver设置侦听,获取mScaleBarLayout的宽和高 79 | LinearLayout mScaleBarLayout = (LinearLayout) view.findViewById(R.id.scale_bar_layout); 80 | OrientationDrawListener mScaleDrawListener = new OrientationDrawListener(mScaleBarLayout); 81 | ViewTreeObserver mScaleObserver = mScaleBarLayout.getViewTreeObserver(); 82 | mScaleObserver.addOnPreDrawListener(mScaleDrawListener); 83 | // 获取SignalScaleBar类实例 84 | mSignalScaleBar = (SignalScaleBar) view.findViewById(R.id.scale_bar); 85 | mSignalScaleBarCallbacks = mSignalScaleBar.getmSignalScaleBarCallbacks(); 86 | } 87 | 88 | @Override 89 | public void onHiddenChanged(boolean hidden) 90 | { 91 | if (hidden) 92 | { 93 | mSatelliteView.setVisibility(View.GONE); 94 | mSignalScaleBar.setVisibility(View.GONE); 95 | } 96 | else 97 | { 98 | mSatelliteView.setVisibility(View.VISIBLE); 99 | mSignalScaleBar.setVisibility(View.VISIBLE); 100 | } 101 | super.onHiddenChanged(hidden); 102 | } 103 | 104 | @Override 105 | public void onDestroyView() 106 | { 107 | super.onDestroyView(); 108 | } 109 | 110 | @Override 111 | public void onDetach() 112 | { 113 | super.onDetach(); 114 | } 115 | 116 | @Override 117 | public void onPause() 118 | { 119 | super.onPause(); 120 | } 121 | 122 | @Override 123 | public void onResume() 124 | { 125 | super.onResume(); 126 | } 127 | 128 | @Override 129 | public void onStart() 130 | { 131 | super.onStart(); 132 | } 133 | 134 | @Override 135 | public void onStop() 136 | { 137 | super.onStop(); 138 | } 139 | 140 | // 内部类,获取绘柱信号强度颜色的layout的宽和高 141 | class OrientationDrawListener implements ViewTreeObserver.OnPreDrawListener 142 | { 143 | private View view; 144 | public OrientationDrawListener(View view) 145 | { 146 | this.view = view; 147 | } 148 | @Override 149 | public boolean onPreDraw() { 150 | view.getViewTreeObserver().removeOnPreDrawListener(this); 151 | mScaleLayoutWidth = view.getWidth(); 152 | mScaleLayoutHeight = view.getHeight(); 153 | mSignalScaleBarCallbacks.updateScaleLayoutSize(OrientationFragment.this); 154 | return true; 155 | } 156 | } 157 | 158 | // 内部类,获取绘卫星方位图的layout的宽和高 159 | class SatelliteViewLayoutListener implements ViewTreeObserver.OnPreDrawListener 160 | { 161 | private View view; 162 | public SatelliteViewLayoutListener(View view) 163 | { 164 | this.view = view; 165 | } 166 | @Override 167 | public boolean onPreDraw() 168 | { 169 | view.getViewTreeObserver().removeOnPreDrawListener(this); 170 | mSatelliteViewWidth = view.getWidth(); 171 | mSatelliteViewHeight = view.getHeight(); 172 | mSatelliteViewCallbacks.updateSatelliteViewSize(OrientationFragment.this); 173 | return true; 174 | } 175 | } 176 | 177 | //定义接口,用于回调 178 | private OrientationCallbacks mOrientationCallbacks = new OrientationCallbacks() 179 | { 180 | @Override 181 | public void updateOrientationViewInfo(SatelliteAdapter satelliteAdapter, boolean isGnssEnabled) 182 | { 183 | if (isInit) 184 | { 185 | if (isGnssEnabled) 186 | { 187 | if (null != satelliteAdapter) 188 | { 189 | visible.setText(String.valueOf(satelliteAdapter.getmVisiable())); 190 | // fixTime.setText(String.valueOf(satelliteAdapter.getmFirstFixTime())); 191 | connect.setText(String.valueOf(satelliteAdapter.getmConnect())); 192 | mSatelliteViewCallbacks.updateSatelliteViewInfo(satelliteAdapter); 193 | } 194 | else 195 | { 196 | initOrientationView(); 197 | } 198 | } 199 | else 200 | { 201 | initOrientationView(); 202 | } 203 | } 204 | } 205 | 206 | @Override 207 | public void updateOrientationViewLocationInfo(boolean isGnssEnabled) 208 | { 209 | if (isInit) 210 | { 211 | if (!isGnssEnabled) 212 | { 213 | initOrientationView(); 214 | } 215 | } 216 | } 217 | }; 218 | 219 | /** 220 | * 设置获取OrientationFragment实例的OrientationCallbacks方法 221 | * @return 222 | */ 223 | public OrientationCallbacks getOrientationCallbacks() 224 | { 225 | return mOrientationCallbacks; 226 | } 227 | 228 | /** 229 | * 初始化显示界面 230 | */ 231 | private void initOrientationView() 232 | { 233 | visible.setText(Constant.GNSS_DATA_ZERO); 234 | // fixTime.setText(Constant.GNSS_DATA_ZERO); 235 | connect.setText(Constant.GNSS_DATA_ZERO); 236 | mSatelliteViewCallbacks.updateSatelliteViewInfo(null); 237 | } 238 | 239 | /** 240 | * 获取表示卫星方位图容器的宽 241 | * @return 242 | */ 243 | public int getmSatelliteViewWidth() 244 | { 245 | return mSatelliteViewWidth; 246 | } 247 | 248 | /** 249 | * 获取表示卫星方位图容器的高 250 | * @return 251 | */ 252 | public int getmSatelliteViewHeight() 253 | { 254 | return mSatelliteViewHeight; 255 | } 256 | 257 | /** 258 | * 获取表示信号颜色容器的宽 259 | * @return 260 | */ 261 | public int getmScaleLayoutWidth() 262 | { 263 | return mScaleLayoutWidth; 264 | } 265 | 266 | /** 267 | * 获取表示信号颜色容器的高 268 | * @return 269 | */ 270 | public int getmScaleLayoutHeight() 271 | { 272 | return mScaleLayoutHeight; 273 | } 274 | 275 | } 276 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/SignalCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import com.tonker.gnss.location.SatelliteAdapter; 4 | 5 | 6 | /** 7 | * SignalFragment用于回调的接口 8 | * 这个接口采用了两个方法,之前是设计了一个方法,可以开关和更新卫星信噪比信息,但是由于侦听分为状态侦听 9 | * 和位置侦听,有时两者同时变化,都会调用这一方法,会给更新带来一定的困扰,因此尝试分成两了两个部分; 10 | * @author newtonker 11 | * @date 2014-06-17 12 | */ 13 | public interface SignalCallbacks 14 | { 15 | /** 16 | * 更新GNSS开关状态信息 17 | * @param isGnssEnabled 检测GNSS是否可用,true:可用, false:不可用 18 | */ 19 | void updateSignalViewSwitch(boolean isGnssEnabled); 20 | 21 | /** 22 | * 更新GNSS定位状态信息 23 | * @param isGnssEnabled 24 | */ 25 | void updateSignalViewFixStatus(boolean isGnssEnabled, String string); 26 | 27 | /** 28 | * 更新GNSS可见卫星,已连接卫星的信息 29 | * @param satelliteAdapter 存放可见卫星数,已连接卫星数,卫星信噪比等信息 30 | * @param isGnssEnabled 检测GNSS是否可用,true:可用, false:不可用 31 | */ 32 | void updateSignalViewSnrInfo(SatelliteAdapter satelliteAdapter, boolean isGnssEnabled); 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/SignalFragment.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import com.tonker.gnss.R; 4 | import com.tonker.gnss.constant.Constant; 5 | import com.tonker.gnss.graphics.*; 6 | import com.tonker.gnss.location.SatelliteAdapter; 7 | 8 | import android.support.v4.app.Fragment; 9 | import android.content.Intent; 10 | import android.os.Bundle; 11 | import android.provider.Settings; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.ViewTreeObserver; 16 | import android.view.View.OnClickListener; 17 | import android.widget.LinearLayout; 18 | import android.widget.RelativeLayout; 19 | import android.widget.TextView; 20 | 21 | /** 22 | * 这个Fragment实现了第一个界面(卫星信噪比)的显示 23 | * 24 | * @author newtonker 25 | * @date 2014-06-17 26 | */ 27 | public class SignalFragment extends Fragment 28 | { 29 | //定义要存放GPS柱状图的容器的宽和高 30 | private int mSnrLayoutWidth; 31 | private int mSnrLayoutHeight; 32 | //定义要存放BDS柱状图的容器的宽和高 33 | private int mBdsSnrLayoutWidth; 34 | private int mBdsSnrLayoutHeight; 35 | //容器中的相应部件 36 | private TextView gnssStatus; 37 | private TextView gnssFixStatus; 38 | private TextView visiableNum; 39 | private TextView connectNum; 40 | private TextView bdsVisiableNum; 41 | private TextView bdsConnectNum; 42 | 43 | private BarChart mBarChart; 44 | private BarChartCallbacks mBarChartCallbacks; 45 | 46 | private BdsBarChart mBdsBarChart; 47 | private BdsBarChartCallbacks mBdsBarChartCallbacks; 48 | 49 | @Override 50 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 51 | { 52 | View view = inflater.inflate(R.layout.tab_a, container, false); 53 | initView(view); 54 | initSignalView(); 55 | return view; 56 | } 57 | 58 | private void initView(View view) 59 | { 60 | //设置标题题目 61 | TextView mTitleText = (TextView) view.findViewById(R.id.title_name_content); 62 | mTitleText.setText(R.string.signal); 63 | 64 | //对mSnrObserver设置侦听,获取mSnrLayout的宽和高 65 | LinearLayout mSnrLayout = (LinearLayout) view.findViewById(R.id.snr_layout); 66 | DrawListener mSnrListener = new DrawListener(mSnrLayout); 67 | ViewTreeObserver mSnrObserver = mSnrLayout.getViewTreeObserver(); 68 | mSnrObserver.addOnPreDrawListener(mSnrListener); 69 | //获取BarChart实例 70 | mBarChart = (BarChart) view.findViewById(R.id.snr_view); 71 | mBarChartCallbacks = mBarChart.getmBarChartCallbacks(); 72 | 73 | //对mBdsSnrObserver设置侦听,获取mBdsSnrLayout的宽和高 74 | LinearLayout mBdsSnrLayout = (LinearLayout) view.findViewById(R.id.bds_snr_layout); 75 | BdsDrawListener mBdsSnrListener = new BdsDrawListener(mBdsSnrLayout); 76 | ViewTreeObserver mBdsSnrObserver = mBdsSnrLayout.getViewTreeObserver(); 77 | mBdsSnrObserver.addOnPreDrawListener(mBdsSnrListener); 78 | //获取mBdsBarChart实例 79 | mBdsBarChart = (BdsBarChart) view.findViewById(R.id.bds_snr_view); 80 | mBdsBarChartCallbacks = mBdsBarChart.getmBdsBarChartCallbacks(); 81 | //获取GNSS开关显示状态 82 | gnssStatus = (TextView) view.findViewById(R.id.gnss_status); 83 | gnssFixStatus = (TextView) view.findViewById(R.id.gnss_fix_status); 84 | visiableNum = (TextView) view.findViewById(R.id.visiable_num); 85 | connectNum = (TextView) view.findViewById(R.id.connect_num); 86 | bdsVisiableNum = (TextView) view.findViewById(R.id.bds_visiable_num); 87 | bdsConnectNum = (TextView) view.findViewById(R.id.bds_connect_num); 88 | 89 | RelativeLayout mSwitchLayout = (RelativeLayout) view.findViewById(R.id.gnss_switch); 90 | //对GNSS开关设置侦听,开启或关闭GNSS 91 | mSwitchLayout.setOnClickListener(mOnClickListener); 92 | } 93 | 94 | @Override 95 | public void onHiddenChanged(boolean hidden) 96 | { 97 | if (hidden) 98 | { 99 | mBarChart.setVisibility(View.GONE); 100 | mBdsBarChart.setVisibility(View.GONE); 101 | } 102 | else 103 | { 104 | mBarChart.setVisibility(View.VISIBLE); 105 | mBdsBarChart.setVisibility(View.VISIBLE); 106 | } 107 | super.onHiddenChanged(hidden); 108 | } 109 | 110 | @Override 111 | public void onDestroyView() 112 | { 113 | super.onDestroyView(); 114 | } 115 | 116 | @Override 117 | public void onDetach() 118 | { 119 | super.onDetach(); 120 | } 121 | 122 | @Override 123 | public void onPause() 124 | { 125 | super.onPause(); 126 | } 127 | 128 | @Override 129 | public void onResume() 130 | { 131 | super.onResume(); 132 | } 133 | 134 | @Override 135 | public void onStart() 136 | { 137 | super.onStart(); 138 | } 139 | 140 | @Override 141 | public void onStop() 142 | { 143 | super.onStop(); 144 | } 145 | 146 | //GNSS开关的侦听类实例 147 | private OnClickListener mOnClickListener = new OnClickListener() 148 | { 149 | @Override 150 | public void onClick(View v) 151 | { 152 | Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 153 | startActivityForResult(intent, 0); 154 | } 155 | }; 156 | 157 | // 内部类,获取绘柱状图区域的layout的宽和高 158 | class DrawListener implements ViewTreeObserver.OnPreDrawListener 159 | { 160 | private View view; 161 | 162 | public DrawListener(View view) 163 | { 164 | this.view = view; 165 | } 166 | 167 | @Override 168 | public boolean onPreDraw() 169 | { 170 | view.getViewTreeObserver().removeOnPreDrawListener(this); 171 | mSnrLayoutWidth = view.getWidth(); 172 | mSnrLayoutHeight = view.getHeight(); 173 | mBarChartCallbacks.updateSnrLayoutSize(SignalFragment.this); 174 | return true; 175 | } 176 | } 177 | 178 | // 内部类,获取绘柱状图区域的layout的宽和高 179 | class BdsDrawListener implements ViewTreeObserver.OnPreDrawListener 180 | { 181 | private View view; 182 | 183 | public BdsDrawListener(View view) 184 | { 185 | this.view = view; 186 | } 187 | 188 | @Override 189 | public boolean onPreDraw() 190 | { 191 | view.getViewTreeObserver().removeOnPreDrawListener(this); 192 | mBdsSnrLayoutWidth = view.getWidth(); 193 | mBdsSnrLayoutHeight = view.getHeight(); 194 | mBdsBarChartCallbacks.updateBdsSnrLayoutSize(SignalFragment.this); 195 | return true; 196 | } 197 | } 198 | 199 | //创建SignalCallbacks接口用于回调 200 | private SignalCallbacks mSignalCallbacks = new SignalCallbacks() 201 | { 202 | @Override 203 | public void updateSignalViewSnrInfo(SatelliteAdapter satelliteAdapter, boolean isGnssEnabled) 204 | { 205 | if (isGnssEnabled) 206 | { 207 | if (null != satelliteAdapter) 208 | { 209 | visiableNum.setText(String.valueOf(satelliteAdapter.getmGpsVisiable())); 210 | connectNum.setText(String.valueOf(satelliteAdapter.getmGpsConnect())); 211 | bdsVisiableNum.setText(String.valueOf(satelliteAdapter.getmBdsVisiable())); 212 | bdsConnectNum.setText(String.valueOf(satelliteAdapter.getmBdsConnect())); 213 | mBarChartCallbacks.updateSatelliteSrn(satelliteAdapter); 214 | mBdsBarChartCallbacks.updateBdsSatelliteSrn(satelliteAdapter); 215 | } 216 | else 217 | { 218 | initSignalView(); 219 | } 220 | } 221 | else 222 | { 223 | initSignalView(); 224 | } 225 | } 226 | 227 | @Override 228 | public void updateSignalViewFixStatus(boolean isGnssEnabled, String s) 229 | { 230 | if (isGnssEnabled) 231 | { 232 | gnssFixStatus.setText(s); 233 | } 234 | else 235 | { 236 | gnssFixStatus.setText(Constant.FIX_STOP); 237 | } 238 | } 239 | 240 | @Override 241 | public void updateSignalViewSwitch(boolean isGnssEnabled) 242 | { 243 | if (isGnssEnabled) 244 | { 245 | gnssStatus.setText(Constant.GNSS_SWITCH_ON); 246 | } 247 | else 248 | { 249 | initSignalView(); 250 | } 251 | } 252 | }; 253 | 254 | /** 255 | * 获取SignalFrament实例的SignalCallbacks接口实例 256 | * 257 | * @return 258 | */ 259 | public SignalCallbacks getSignalCallbacks() 260 | { 261 | return mSignalCallbacks; 262 | } 263 | 264 | /** 265 | * 初始化显示界面 266 | */ 267 | private void initSignalView() 268 | { 269 | gnssStatus.setText(Constant.GNSS_SWITCH_OFF); 270 | gnssFixStatus.setText(Constant.FIX_STOP); 271 | visiableNum.setText(Constant.GNSS_DATA_ZERO); 272 | connectNum.setText(Constant.GNSS_DATA_ZERO); 273 | bdsVisiableNum.setText(Constant.GNSS_DATA_ZERO); 274 | bdsConnectNum.setText(Constant.GNSS_DATA_ZERO); 275 | mBarChartCallbacks.updateSatelliteSrn(null); 276 | mBdsBarChartCallbacks.updateBdsSatelliteSrn(null); 277 | } 278 | 279 | /** 280 | * 获取SnrLayout的宽 281 | * 282 | * @return 283 | */ 284 | public int getmSnrLayoutWidth() 285 | { 286 | return mSnrLayoutWidth; 287 | } 288 | 289 | /** 290 | * 获取SnrLayout的高 291 | * 292 | * @return 293 | */ 294 | public int getmSnrLayoutHeight() 295 | { 296 | return mSnrLayoutHeight; 297 | } 298 | 299 | /** 300 | * 获取BdsSnrLayout的高 301 | * 302 | * @return 303 | */ 304 | public int getmBdsSnrLayoutWidth() 305 | { 306 | return mBdsSnrLayoutWidth; 307 | } 308 | 309 | /** 310 | * 获取BdsSnrLayout的宽 311 | * 312 | * @return 313 | */ 314 | public int getmBdsSnrLayoutHeight() 315 | { 316 | return mBdsSnrLayoutHeight; 317 | } 318 | 319 | } 320 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/TimeCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import android.location.Location; 4 | 5 | /** 6 | * TimeFragment用于回调的接口(可优化合并) 7 | * @author newtonker 8 | * @date 2014-06-17 9 | */ 10 | public interface TimeCallbacks 11 | { 12 | /** 13 | * 更新UTC日期、时间,本地日期、时间,日出时间,日落时间,经纬度,方向角,海拔,速度,磁偏角等信息 14 | * @param location 包括UTC时间,本地时间,日出日落时间,经纬度,方向角,海拔,速度,磁偏角等信息 15 | * @param isGnssEnabled 检测GNSS是否可用,true:可用, false:不可用 16 | */ 17 | void updateTimeViewInfo(Location location, boolean isGnssEnabled); 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/fragment/TimeFragment.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.fragment; 2 | 3 | import java.sql.Timestamp; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Locale; 6 | import java.util.TimeZone; 7 | 8 | import com.tonker.gnss.R; 9 | import com.tonker.gnss.constant.Constant; 10 | 11 | import android.support.v4.app.Fragment; 12 | import android.view.View; 13 | import android.view.LayoutInflater; 14 | import android.view.ViewGroup; 15 | import android.widget.TextView; 16 | import android.content.BroadcastReceiver; 17 | import android.content.Context; 18 | import android.content.Intent; 19 | import android.content.IntentFilter; 20 | import android.content.SharedPreferences; 21 | import android.location.Location; 22 | import android.os.Bundle; 23 | import android.preference.PreferenceManager; 24 | 25 | /** 26 | * 这个Fragment实现了第三个界面(时间坐标)的显示 27 | * 28 | * @author newtonker 29 | * @date 2014-06-17 30 | */ 31 | public class TimeFragment extends Fragment 32 | { 33 | //设置标志位,判断TimeFragment的onCreateView是否已经创建,updateTimeViewInfo时用 34 | private boolean isInit = false; 35 | 36 | //获取容器中的部件 37 | private TextView utcDate; 38 | private TextView utcTime; 39 | private TextView localDate; 40 | private TextView localTime; 41 | private TextView longitude; 42 | private TextView latitude; 43 | private TextView accuracyValue; 44 | private TextView altitude; 45 | private TextView speed; 46 | private TextView bearing; 47 | 48 | //处理日期时间用到的相关变量 49 | private TimeZone mUtcTimeZone; 50 | private SimpleDateFormat mUtcDateFormat; 51 | private SimpleDateFormat mUtcTimeFormat; 52 | private SimpleDateFormat mLocalDateFormat; 53 | private SimpleDateFormat mLocalTimeFormat; 54 | 55 | 56 | // 计算经纬度时用到的变量 57 | private SharedPreferences mPreferences; 58 | 59 | //设置显示变量的各个格式,初始化是选择默认格式 60 | private int mLongitudeFormat = Location.FORMAT_DEGREES; 61 | private String mAccuracyFormat = Constant.DECIMALS_FORMAT; 62 | private String mAltitudeFormat = Constant.DECIMALS_FORMAT; 63 | private String mSpeedFormat = Constant.DECIMALS_FORMAT; 64 | private String mBearingFormat = Constant.DECIMALS_FORMAT; 65 | 66 | //更新格式时用 67 | private Context mContext; 68 | private TimeBroadcastReceiver mBroadcastReceiver; 69 | 70 | @Override 71 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 72 | { 73 | View view = inflater.inflate(R.layout.tab_c, container, false); 74 | 75 | mContext = inflater.getContext(); 76 | 77 | initView(view); 78 | //初始化显示界面 79 | initTimeView(); 80 | isInit = true; 81 | //初始化一些变量 82 | mUtcTimeZone = TimeZone.getTimeZone("Etc/GMT+0"); 83 | //首先判断设置的文件夹是否存在,如果存在则使用其中的配置,如果不存在则使用默认格式 84 | mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); 85 | if (null == mPreferences) 86 | { 87 | setDefaultFormat(); 88 | } 89 | else 90 | { 91 | setAdapterFormat(); 92 | } 93 | 94 | //设置广播接收实例,并增加广播过滤器 95 | mBroadcastReceiver = new TimeBroadcastReceiver(); 96 | IntentFilter filter = new IntentFilter(); 97 | filter.addAction(Constant.UPDATE_DATE_FORMAT); 98 | filter.addAction(Constant.UPDATE_TIME_FORMAT); 99 | filter.addAction(Constant.UPDATE_LONGITUDE_FORMAT); 100 | filter.addAction(Constant.UPDATE_ACCURACY_FORMAT); 101 | filter.addAction(Constant.UPDATE_ALTITUDE_FORMAT); 102 | filter.addAction(Constant.UPDATE_SPEED_FORMAT); 103 | filter.addAction(Constant.UPDATE_BEARING_FORMAT); 104 | filter.addAction(Constant.UPDATE_DEFAULT_FORMAT); 105 | 106 | mContext.registerReceiver(mBroadcastReceiver, filter); 107 | return view; 108 | } 109 | 110 | /** 111 | * 初始化视图 112 | * 113 | * @param view 114 | */ 115 | private void initView(View view) 116 | { 117 | //设置标题题目 118 | TextView mTitleText = (TextView) view.findViewById(R.id.title_name_content); 119 | mTitleText.setText(R.string.time); 120 | 121 | //获取各个显示文本框 122 | utcDate = (TextView) view.findViewById(R.id.UTC_date); 123 | utcTime = (TextView) view.findViewById(R.id.UTC_time); 124 | localDate = (TextView) view.findViewById(R.id.local_date); 125 | localTime = (TextView) view.findViewById(R.id.local_time); 126 | latitude = (TextView) view.findViewById(R.id.latitude_value); 127 | longitude = (TextView) view.findViewById(R.id.longitude_value); 128 | accuracyValue = (TextView) view.findViewById(R.id.accuracy_value); 129 | altitude = (TextView) view.findViewById(R.id.altitude_value); 130 | speed = (TextView) view.findViewById(R.id.speed_value); 131 | bearing = (TextView) view.findViewById(R.id.direction_angle); 132 | } 133 | 134 | @Override 135 | public void onDestroy() 136 | { 137 | //Fragment销毁时则注销相关侦听 138 | mContext.unregisterReceiver(mBroadcastReceiver); 139 | mBroadcastReceiver = null; 140 | super.onDestroy(); 141 | } 142 | 143 | //创建广播接收类,用于介绍设置改变后所发出的广播信息 144 | private class TimeBroadcastReceiver extends BroadcastReceiver 145 | { 146 | private String action; 147 | 148 | @Override 149 | public void onReceive(Context context, Intent intent) 150 | { 151 | action = intent.getAction(); 152 | mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); 153 | if (null == mPreferences) 154 | { 155 | return; 156 | } 157 | if (action.equals(Constant.UPDATE_DATE_FORMAT)) 158 | { 159 | setDateFormat(mPreferences.getInt(Constant.SETTING_DATE_FORMAT, 0)); 160 | } 161 | else if (action.equals(Constant.UPDATE_TIME_FORMAT)) 162 | { 163 | setTimeFormat(mPreferences.getInt(Constant.SETTING_TIME_FORMAT, 0)); 164 | } 165 | else if (action.equals(Constant.UPDATE_LONGITUDE_FORMAT)) 166 | { 167 | setLogitudeFormat(mPreferences.getInt(Constant.SETTING_LONGITUDE_FORMAT, 0)); 168 | } 169 | else if (action.equals(Constant.UPDATE_ACCURACY_FORMAT)) 170 | { 171 | setAccuracyFormat(mPreferences.getInt(Constant.SETTING_ACCURACY_FORMAT, 0)); 172 | } 173 | else if (action.equals(Constant.UPDATE_ALTITUDE_FORMAT)) 174 | { 175 | setAltitudeFormat(mPreferences.getInt(Constant.SETTING_ALTITUDE_FORMAT, 0)); 176 | } 177 | else if (action.equals(Constant.UPDATE_SPEED_FORMAT)) 178 | { 179 | setSpeedFormat(mPreferences.getInt(Constant.SETTING_SPEED_FORMAT, 0)); 180 | } 181 | else if (action.equals(Constant.UPDATE_BEARING_FORMAT)) 182 | { 183 | setBearingFormat(mPreferences.getInt(Constant.SETTING_BEARING_FORMAT, 0)); 184 | } 185 | else if (action.equals(Constant.UPDATE_DEFAULT_FORMAT)) 186 | { 187 | if (mPreferences.getBoolean(Constant.SETTING_DEFAULT_FORMAT, false)) 188 | { 189 | setDefaultFormat(); 190 | } 191 | else 192 | { 193 | setAdapterFormat(); 194 | } 195 | } 196 | } 197 | } 198 | 199 | /** 200 | * 设置日期格式 201 | * 202 | * @param id 203 | */ 204 | private void setDateFormat(int id) 205 | { 206 | switch (id) 207 | { 208 | case 1: 209 | mUtcDateFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()); 210 | mUtcDateFormat.setTimeZone(mUtcTimeZone); 211 | mLocalDateFormat = new SimpleDateFormat("MM/dd/yyyy", Locale.getDefault()); 212 | break; 213 | case 2: 214 | mUtcDateFormat = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); 215 | mUtcDateFormat.setTimeZone(mUtcTimeZone); 216 | mLocalDateFormat = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()); 217 | break; 218 | default: 219 | mUtcDateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()); 220 | mUtcDateFormat.setTimeZone(mUtcTimeZone); 221 | mLocalDateFormat = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()); 222 | break; 223 | } 224 | } 225 | 226 | /** 227 | * 设置时间格式 228 | * 229 | * @param id 230 | */ 231 | private void setTimeFormat(int id) 232 | { 233 | switch (id) 234 | { 235 | case 1: 236 | mUtcTimeFormat = new SimpleDateFormat("hh:mm:ss", Locale.getDefault()); 237 | mUtcTimeFormat.setTimeZone(mUtcTimeZone); 238 | mLocalTimeFormat = new SimpleDateFormat("hh:mm:ss", Locale.getDefault()); 239 | break; 240 | default: 241 | mUtcTimeFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); 242 | mUtcTimeFormat.setTimeZone(mUtcTimeZone); 243 | mLocalTimeFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); 244 | break; 245 | } 246 | } 247 | 248 | /** 249 | * 设置坐标系格式 250 | * 251 | * @param id 252 | */ 253 | private void setLogitudeFormat(int id) 254 | { 255 | switch (id) 256 | { 257 | case 1: 258 | mLongitudeFormat = Location.FORMAT_MINUTES; 259 | break; 260 | case 2: 261 | mLongitudeFormat = Location.FORMAT_SECONDS; 262 | break; 263 | default: 264 | mLongitudeFormat = Location.FORMAT_DEGREES; 265 | break; 266 | } 267 | } 268 | 269 | /** 270 | * 设置准确度的格式 271 | * 272 | * @param id 273 | */ 274 | private void setAccuracyFormat(int id) 275 | { 276 | switch (id) 277 | { 278 | case 1: 279 | mAccuracyFormat = Constant.INTEGER_FORMAT; 280 | break; 281 | default: 282 | mAccuracyFormat = Constant.DECIMALS_FORMAT; 283 | break; 284 | } 285 | } 286 | 287 | /** 288 | * 设置海拔的格式 289 | * 290 | * @param id 291 | */ 292 | private void setAltitudeFormat(int id) 293 | { 294 | switch (id) 295 | { 296 | case 1: 297 | mAltitudeFormat = Constant.INTEGER_FORMAT; 298 | break; 299 | default: 300 | mAltitudeFormat = Constant.DECIMALS_FORMAT; 301 | break; 302 | } 303 | } 304 | 305 | /** 306 | * 设置准确度的格式 307 | * 308 | * @param id 309 | */ 310 | private void setSpeedFormat(int id) 311 | { 312 | switch (id) 313 | { 314 | case 1: 315 | mSpeedFormat = Constant.INTEGER_FORMAT; 316 | break; 317 | default: 318 | mSpeedFormat = Constant.DECIMALS_FORMAT; 319 | break; 320 | } 321 | } 322 | 323 | /** 324 | * 设置方向角的格式 325 | * 326 | * @param id 327 | */ 328 | private void setBearingFormat(int id) 329 | { 330 | switch (id) 331 | { 332 | case 1: 333 | mBearingFormat = Constant.INTEGER_FORMAT; 334 | break; 335 | default: 336 | mBearingFormat = Constant.DECIMALS_FORMAT; 337 | break; 338 | } 339 | } 340 | 341 | /** 342 | * 设置default的格式 343 | */ 344 | private void setDefaultFormat() 345 | { 346 | setDateFormat(0); 347 | setTimeFormat(0); 348 | setLogitudeFormat(0); 349 | setAccuracyFormat(0); 350 | setAltitudeFormat(0); 351 | setSpeedFormat(0); 352 | setBearingFormat(0); 353 | } 354 | 355 | /** 356 | * 设置自适应配置的格式 357 | */ 358 | private void setAdapterFormat() 359 | { 360 | setDateFormat(mPreferences.getInt(Constant.SETTING_DATE_FORMAT, 0)); 361 | setTimeFormat(mPreferences.getInt(Constant.SETTING_TIME_FORMAT, 0)); 362 | setLogitudeFormat(mPreferences.getInt(Constant.SETTING_LONGITUDE_FORMAT, 0)); 363 | setAccuracyFormat(mPreferences.getInt(Constant.SETTING_ACCURACY_FORMAT, 0)); 364 | setAltitudeFormat(mPreferences.getInt(Constant.SETTING_ALTITUDE_FORMAT, 0)); 365 | setSpeedFormat(mPreferences.getInt(Constant.SETTING_SPEED_FORMAT, 0)); 366 | setBearingFormat(mPreferences.getInt(Constant.SETTING_BEARING_FORMAT, 0)); 367 | } 368 | 369 | /** 370 | * 根据获取到的Location,得到日期时间、经纬度等信息并显示 371 | * 372 | * @param location 373 | * @param isGnssEnabled 374 | */ 375 | private void updateTimeView(Location location, boolean isGnssEnabled) 376 | { 377 | if (isGnssEnabled) 378 | { 379 | if (null != location) 380 | { 381 | updateDateAndTime(location); 382 | updateSpeedAndBearing(location); 383 | } 384 | else 385 | { 386 | initTimeView(); 387 | } 388 | } 389 | else 390 | { 391 | initTimeView(); 392 | } 393 | } 394 | 395 | /** 396 | * 更新UTC日期、时间及本地日期和时间 397 | * 398 | * @param location 399 | */ 400 | public void updateDateAndTime(Location location) 401 | { 402 | Timestamp mTimestamp = new Timestamp(location.getTime()); 403 | String mLocalDate = mLocalDateFormat.format(mTimestamp); 404 | String mLocalTime = mLocalTimeFormat.format(mTimestamp); 405 | String mUtcDate = mUtcDateFormat.format(mTimestamp); 406 | String mUtcTime = mUtcTimeFormat.format(mTimestamp); 407 | //更新文本框显示 408 | utcDate.setText(mUtcDate); 409 | utcTime.setText(mUtcTime); 410 | localDate.setText(mLocalDate); 411 | localTime.setText(mLocalTime); 412 | } 413 | 414 | /** 415 | * 转换经纬度的公式 416 | * 417 | * @param string 418 | * @return 419 | */ 420 | private String convertString(String string, int id) 421 | { 422 | StringBuilder mStringBuilder = new StringBuilder(); 423 | int index1, index2, index3; 424 | switch (id) 425 | { 426 | case Location.FORMAT_MINUTES: 427 | index1 = string.indexOf(':'); 428 | index2 = string.length() - 1; 429 | index3 = 0; 430 | 431 | mStringBuilder.append(string.substring(0, index1)).append('°').append(string.substring(index1 + 1, index2)).append('′'); 432 | return mStringBuilder.toString(); 433 | case Location.FORMAT_SECONDS: 434 | index1 = string.indexOf(':'); 435 | index2 = string.indexOf(':', index1 + 1); 436 | index3 = string.length() - 1; 437 | 438 | mStringBuilder.append(string.substring(0, index1)).append('°').append(string.substring(index1 + 1, index2)).append('′').append(string.substring(index2 + 1, index3)).append('″'); 439 | return mStringBuilder.toString(); 440 | default: 441 | index1 = string.length() - 1; 442 | index2 = 0; 443 | index3 = 0; 444 | 445 | mStringBuilder.append(string.substring(0, index1)).append('°'); 446 | return mStringBuilder.toString(); 447 | } 448 | } 449 | 450 | /** 451 | * 更新经纬度、高度、准确度、速度及方向角等信息 452 | * 453 | * @param location 454 | */ 455 | public void updateSpeedAndBearing(Location location) 456 | { 457 | double longitudeValue = location.getLongitude(); 458 | double latitudeValue = location.getLatitude(); 459 | String longitudeTag; 460 | String latitudeTag; 461 | if (longitudeValue > 0) 462 | { 463 | longitudeTag = "E "; 464 | } 465 | else 466 | { 467 | longitudeTag = "W "; 468 | } 469 | if (latitudeValue > 0) 470 | { 471 | latitudeTag = "N "; 472 | } 473 | else 474 | { 475 | latitudeTag = "S "; 476 | } 477 | //获取经纬度 478 | String mLongitude = convertString(Location.convert(Math.abs(longitudeValue), mLongitudeFormat), mLongitudeFormat); 479 | String mLatitude = convertString(Location.convert(Math.abs(latitudeValue), mLongitudeFormat), mLongitudeFormat); 480 | //更新View显示 481 | longitude.setText(longitudeTag + mLongitude); 482 | latitude.setText(latitudeTag + mLatitude); 483 | //获取准确度、高度、速度及方向角等信息 484 | String mAccuracy = String.format(Locale.getDefault(), mAccuracyFormat, location.getAccuracy()); 485 | String mAltitude = String.format(Locale.getDefault(), mAltitudeFormat, location.getAltitude()); 486 | String mSpeed = String.format(Locale.getDefault(), mSpeedFormat, location.getSpeed()); 487 | String mBearing = String.format(Locale.getDefault(), mBearingFormat, location.getBearing()); 488 | //更新View显示 489 | accuracyValue.setText(mAccuracy); 490 | altitude.setText(mAltitude); 491 | speed.setText(mSpeed); 492 | bearing.setText(mBearing); 493 | } 494 | 495 | //定义一个TimeCallbacks接口,实现其方法,用于回调 496 | private TimeCallbacks mTimeCallbacks = new TimeCallbacks() 497 | { 498 | @Override 499 | public void updateTimeViewInfo(Location location, boolean isGnssEnabled) 500 | { 501 | if (isInit) 502 | { 503 | updateTimeView(location, isGnssEnabled); 504 | } 505 | } 506 | }; 507 | 508 | /** 509 | * 获取TimeCallbacks接口的方法 510 | * 511 | * @return 512 | */ 513 | public TimeCallbacks getTimeCallbacks() 514 | { 515 | return mTimeCallbacks; 516 | } 517 | 518 | /** 519 | * 初始化显示界面 520 | */ 521 | private void initTimeView() 522 | { 523 | //UTC日期、时间等信息还需要计算 524 | utcDate.setText(Constant.GNSS_DATA_UNKNOWN); 525 | utcTime.setText(Constant.GNSS_DATA_UNKNOWN); 526 | localDate.setText(Constant.GNSS_DATA_UNKNOWN); 527 | localTime.setText(Constant.GNSS_DATA_UNKNOWN); 528 | //经纬度信息还需要处理 529 | longitude.setText(Constant.GNSS_DATA_UNKNOWN); 530 | latitude.setText(Constant.GNSS_DATA_UNKNOWN); 531 | accuracyValue.setText(Constant.GNSS_DATA_UNKNOWN); 532 | altitude.setText(Constant.GNSS_DATA_UNKNOWN); 533 | speed.setText(Constant.GNSS_DATA_UNKNOWN); 534 | bearing.setText(Constant.GNSS_DATA_UNKNOWN); 535 | } 536 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/BarChart.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import java.util.List; 4 | 5 | import com.tonker.gnss.R; 6 | import com.tonker.gnss.constant.Constant; 7 | import com.tonker.gnss.fragment.SignalFragment; 8 | import com.tonker.gnss.location.MySatellite; 9 | import com.tonker.gnss.location.SatelliteAdapter; 10 | 11 | import android.view.SurfaceHolder; 12 | import android.view.SurfaceHolder.Callback; 13 | import android.view.SurfaceView; 14 | import android.content.Context; 15 | import android.content.res.Resources; 16 | import android.graphics.Canvas; 17 | import android.graphics.Color; 18 | import android.graphics.DashPathEffect; 19 | import android.graphics.Paint; 20 | import android.graphics.PathEffect; 21 | import android.util.AttributeSet; 22 | 23 | /** 24 | * 这一个类用来画柱状图 25 | * 26 | * @author newtonker 27 | * @date 2014-06-07 28 | */ 29 | public class BarChart extends SurfaceView implements Callback 30 | { 31 | //相邻柱状图间距(柱状图2左侧-柱状图1右侧) 32 | private int mBarChartSpacing; 33 | //设置坐标系距离上下左右的边距 34 | private int mMarginValue; 35 | private int mMarginTop; 36 | private int mMarginBottom; 37 | //设置卫星号的字体所占高度 38 | private int mTextSize; 39 | //设置当前界面的背景颜色,更新画布时用 40 | private int mBackgroundColor; 41 | 42 | //坐标系左边距(X轴坐标) 43 | private int mBorderLeft; 44 | //坐标系右边距(X轴坐标) 45 | private int mBorderRight; 46 | //坐标系上边距(Y轴坐标) 47 | private int mBorderTop; 48 | //坐标系下边距(Y轴坐标) 49 | private int mBorderBottom; 50 | //坐标系刻度线的间距 51 | private int mLineGap; 52 | //相邻柱状图间距(柱状图2左侧-柱状图1左侧) 53 | private int mBarGap; 54 | //平均每SNR所占像素值 55 | private int mSnrGap; 56 | 57 | //设置SurfaceView标志位,若已建立则设置为true,在更新柱状图时需检测这一状态 58 | private boolean isSurfaceViewCreated = false; 59 | 60 | //定义坐标画笔 61 | private Paint mDashedPaint; 62 | private Paint mSolidPaint; 63 | //定义柱状图画笔 64 | boolean isUsedInFix; 65 | // 设置柱状图画笔属性 66 | private Paint mChartPaint; 67 | // 设置文本画笔属性 68 | private Paint mTextPaint; 69 | //定义一个SatelliteAdapter用于缓存 70 | private SatelliteAdapter mSatelliteAdapter; 71 | 72 | //创建一个SurfaceHolder 73 | SurfaceHolder mSurfaceHolder = null; 74 | 75 | //constructor 76 | public BarChart(Context context) 77 | { 78 | super(context); 79 | } 80 | 81 | public BarChart(Context context, AttributeSet attributeSet) 82 | { 83 | super(context, attributeSet); 84 | //设置置顶 85 | setZOrderOnTop(true); 86 | mSurfaceHolder = this.getHolder(); 87 | mSurfaceHolder.addCallback(this); 88 | 89 | Resources mResources = context.getResources(); 90 | mMarginValue = (int) mResources.getDimension(R.dimen.layout_spacing); 91 | mMarginTop = (int) mResources.getDimension(R.dimen.bar_chart_margin_top); 92 | mMarginBottom = (int) mResources.getDimension(R.dimen.bar_chart_margin_bottom); 93 | mTextSize = (int) mResources.getDimension(R.dimen.title_font_size); 94 | mBackgroundColor = mResources.getColor(R.color.background_color); 95 | mBarChartSpacing = (int) mResources.getDimension(R.dimen.bar_chart_spacing); 96 | //设置坐标系的实线虚线画笔,配置mDashedPaint画虚线 97 | mDashedPaint = new Paint(); 98 | mDashedPaint.setColor(Color.BLACK); 99 | mDashedPaint.setAntiAlias(true); 100 | mDashedPaint.setStrokeWidth(1); 101 | mDashedPaint.setStyle(Paint.Style.STROKE); 102 | PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 1); 103 | mDashedPaint.setPathEffect(effects); 104 | // 配置solidPaint画实线 105 | mSolidPaint = new Paint(); 106 | mSolidPaint.setColor(Color.BLACK); 107 | mSolidPaint.setAntiAlias(true); 108 | mSolidPaint.setStrokeWidth(1); 109 | mSolidPaint.setStyle(Paint.Style.FILL); 110 | //设置画柱状图的画笔颜色,设置柱状图画笔属性 111 | mChartPaint = new Paint(); 112 | mChartPaint.setAntiAlias(true); 113 | mChartPaint.setStyle(Paint.Style.FILL); 114 | // 设置文本画笔属性 115 | mTextPaint = new Paint(); 116 | mTextPaint.setAntiAlias(true); 117 | mTextPaint.setTextSize(mTextSize); 118 | } 119 | 120 | @Override 121 | public void surfaceCreated(SurfaceHolder holder) 122 | { 123 | isSurfaceViewCreated = true; 124 | } 125 | 126 | @Override 127 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 128 | { 129 | isSurfaceViewCreated = true; 130 | new DrawBarThread(holder, mSatelliteAdapter).start(); 131 | } 132 | 133 | @Override 134 | public void surfaceDestroyed(SurfaceHolder holder) 135 | { 136 | isSurfaceViewCreated = false; 137 | } 138 | 139 | //创建BarChartCallbacks接口,用于回调,该接口实现了根据卫星信息画柱状图 140 | private BarChartCallbacks mBarChartCallbacks = new BarChartCallbacks() 141 | { 142 | @Override 143 | public void updateSnrLayoutSize(SignalFragment signalFragment) 144 | { 145 | int mSnrLayoutWidth = signalFragment.getmSnrLayoutWidth(); 146 | int mSnrLayoutHeight = signalFragment.getmSnrLayoutHeight(); 147 | //计算坐标系的边缘起点、终点坐标以及柱状图间隔,单位信噪比像素值 148 | mBorderLeft = mMarginValue; 149 | mBorderTop = mMarginTop + mTextSize; 150 | mBorderRight = mSnrLayoutWidth - mMarginValue; 151 | mBorderBottom = mSnrLayoutHeight - mMarginBottom - mTextSize; 152 | mLineGap = (mBorderBottom - mBorderTop) / (Constant.LINE_NUM - 1); 153 | mBarGap = (mBorderRight - mBorderLeft) / Constant.BAR_NUM; 154 | mSnrGap = (mBorderBottom - mBorderTop) / Constant.MAX_SNR; 155 | } 156 | 157 | @Override 158 | public void updateSatelliteSrn(SatelliteAdapter satelliteAdapter) 159 | { 160 | //首先判断SurfaceView是否已建立 161 | mSatelliteAdapter = satelliteAdapter; 162 | if (isSurfaceViewCreated) 163 | { 164 | new DrawBarThread(mSurfaceHolder, mSatelliteAdapter).start(); 165 | } 166 | } 167 | }; 168 | 169 | //创建一个新的线程用于在SurfaceView中绘图 170 | private class DrawBarThread extends Thread 171 | { 172 | private Canvas mThreadCanvas; 173 | private SatelliteAdapter mThreadSatelliteAdapter; 174 | private SurfaceHolder mThreadHolder; 175 | 176 | public DrawBarThread(SurfaceHolder surfaceHolder, SatelliteAdapter satelliteAdapter) 177 | { 178 | mThreadHolder = surfaceHolder; 179 | mThreadSatelliteAdapter = satelliteAdapter; 180 | } 181 | 182 | @Override 183 | public void run() 184 | { 185 | synchronized (mThreadHolder) 186 | { 187 | mThreadCanvas = mThreadHolder.lockCanvas(); 188 | drawCoordinate(mThreadCanvas); 189 | drawBarChart(mThreadSatelliteAdapter, mThreadCanvas); 190 | mThreadHolder.unlockCanvasAndPost(mThreadCanvas); 191 | } 192 | } 193 | } 194 | 195 | /** 196 | * 获取实例的接口 197 | * 198 | * @return 199 | */ 200 | public BarChartCallbacks getmBarChartCallbacks() 201 | { 202 | return mBarChartCallbacks; 203 | } 204 | 205 | /** 206 | * 画坐标 207 | * 208 | * @param canvas 209 | */ 210 | public void drawCoordinate(Canvas canvas) 211 | { 212 | if (null != canvas) 213 | { 214 | //重新画背景 215 | canvas.drawColor(mBackgroundColor); 216 | //画坐标系,先画实线 217 | canvas.drawLine(mBorderLeft, mBorderBottom, mBorderRight, mBorderBottom, mSolidPaint); 218 | //再画虚线 219 | for (int i = 1; i < Constant.LINE_NUM; i++) 220 | { 221 | canvas.drawLine(mBorderLeft, mBorderTop + (i - 1) * mLineGap, mBorderRight, mBorderTop + (i - 1) * mLineGap, mDashedPaint); 222 | } 223 | } 224 | } 225 | 226 | /** 227 | * 画柱状图 228 | * 229 | * @param satelliteAdapter 230 | * @param canvas 231 | */ 232 | public void drawBarChart(SatelliteAdapter satelliteAdapter, Canvas canvas) 233 | { 234 | if (null == satelliteAdapter || null == satelliteAdapter.getmGpsSatelliteList() || null == canvas) 235 | { 236 | return; 237 | } 238 | int mSnr = 0; 239 | int mPrn = 0; 240 | int mGpsSatelliteSize = 0; 241 | isUsedInFix = false; 242 | List mGpsSatelliteList = satelliteAdapter.getmGpsSatelliteList(); 243 | mGpsSatelliteSize = mGpsSatelliteList.size() < Constant.BAR_NUM ? mGpsSatelliteList.size() : Constant.BAR_NUM; 244 | 245 | MySatellite mGpsSatellite; 246 | for (int i = 0; i < mGpsSatelliteSize; i++) 247 | { 248 | mGpsSatellite = mGpsSatelliteList.get(i); 249 | isUsedInFix = mGpsSatellite.usedInFix(); 250 | mSnr = (int) mGpsSatellite.getSnr(); 251 | mPrn = mGpsSatellite.getPrn(); 252 | // 判断柱状图颜色 253 | if (isUsedInFix) 254 | { 255 | if (mSnr >= 40) 256 | { 257 | mChartPaint.setColor(Color.BLUE); 258 | } 259 | else if (mSnr >= 30) 260 | { 261 | mChartPaint.setColor(Color.GREEN); 262 | } 263 | else if (mSnr >= 20) 264 | { 265 | mChartPaint.setColor(Color.YELLOW); 266 | } 267 | else if (mSnr >= 10) 268 | { 269 | mChartPaint.setColor(Color.MAGENTA); 270 | } 271 | else 272 | { 273 | mChartPaint.setColor(Color.RED); 274 | } 275 | } 276 | else 277 | { 278 | mChartPaint.setColor(Color.GRAY); 279 | } 280 | // 卫星号 281 | canvas.drawText(String.valueOf(mPrn), mBorderLeft + mBarGap * i, mBorderBottom + mTextSize, mTextPaint); 282 | // 柱状图 283 | canvas.drawRect(mBorderLeft + mBarGap * i, mBorderBottom - mSnr * mSnrGap, mBorderLeft + mBarGap * (i + 1) - mBarChartSpacing, mBorderBottom, mChartPaint); 284 | // 信噪比值 285 | canvas.drawText(String.valueOf(mSnr), mBorderLeft + mBarGap * i, mBorderBottom - (mSnr * mSnrGap), mTextPaint); 286 | } 287 | } 288 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/BarChartCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import com.tonker.gnss.fragment.SignalFragment; 4 | import com.tonker.gnss.location.SatelliteAdapter; 5 | 6 | 7 | /** 8 | * 定义一个回调接口,该接口中提供方法来获取SrnLayout的尺寸,并更新卫星信噪比的柱状图 9 | * @author newtonker 10 | * @date 2014-06-18 11 | */ 12 | public interface BarChartCallbacks 13 | { 14 | /** 15 | * 获取SrnLayout的尺寸(宽和高) 16 | * @param signalFragment 17 | */ 18 | void updateSnrLayoutSize(SignalFragment signalFragment); 19 | 20 | /** 21 | * 获取可见卫星的信噪比并绘制信噪比柱状图 22 | * @param satelliteAdapter 23 | */ 24 | void updateSatelliteSrn(SatelliteAdapter satelliteAdapter); 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/BdsBarChart.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import java.util.List; 4 | 5 | import com.tonker.gnss.R; 6 | import com.tonker.gnss.constant.Constant; 7 | import com.tonker.gnss.fragment.SignalFragment; 8 | import com.tonker.gnss.location.MySatellite; 9 | import com.tonker.gnss.location.SatelliteAdapter; 10 | 11 | import android.content.Context; 12 | import android.content.res.Resources; 13 | import android.graphics.Canvas; 14 | import android.graphics.Color; 15 | import android.graphics.DashPathEffect; 16 | import android.graphics.Paint; 17 | import android.graphics.PathEffect; 18 | import android.util.AttributeSet; 19 | import android.view.SurfaceHolder; 20 | import android.view.SurfaceView; 21 | import android.view.SurfaceHolder.Callback; 22 | 23 | /** 24 | * 这一个类用来画BDS柱状图 25 | * 26 | * @author newtonker 27 | * @date 2014-06-07 28 | */ 29 | public class BdsBarChart extends SurfaceView implements Callback 30 | { 31 | // 相邻柱状图间距(柱状图2左侧-柱状图1右侧) 32 | private int mBdsBarChartSpacing; 33 | //设置坐标系距离上下左右的边距 34 | private int mMarginValue; 35 | private int mMarginTop; 36 | private int mMarginBottom; 37 | // 设置卫星号的字体所占高度 38 | private int mTextSize; 39 | //设置当前界面的背景颜色,更新画布时用 40 | private int mBackgroundColor; 41 | 42 | //坐标系左边距(X轴坐标) 43 | private int mBorderLeft; 44 | //坐标系右边距(X轴坐标) 45 | private int mBorderRight; 46 | //坐标系上边距(Y轴坐标) 47 | private int mBorderTop; 48 | //坐标系下边距(Y轴坐标) 49 | private int mBorderBottom; 50 | //坐标系刻度线的间距 51 | private int mLineGap; 52 | //相邻柱状图间距(柱状图2左侧-柱状图1左侧) 53 | private int mBarGap; 54 | //平均每SNR所占像素值 55 | private int mSnrGap; 56 | 57 | //设置SurfaceView标志位,若已建立则设置为true,在更新柱状图时需检测这一状态 58 | private boolean isSurfaceViewCreated = false; 59 | 60 | //定义坐标画笔 61 | private Paint mDashedPaint; 62 | private Paint mSolidPaint; 63 | //定义柱状图画笔 64 | boolean isUsedInFix; 65 | // 设置柱状图画笔属性 66 | private Paint mChartPaint; 67 | // 设置文本画笔属性 68 | private Paint mTextPaint; 69 | //定义一个SatelliteAdapter用于缓存 70 | private SatelliteAdapter mSatelliteAdapter; 71 | 72 | //创建一个SurfaceHolder 73 | SurfaceHolder mSurfaceHolder = null; 74 | 75 | //constructor 76 | public BdsBarChart(Context context) 77 | { 78 | super(context); 79 | } 80 | 81 | public BdsBarChart(Context context, AttributeSet attributeSet) 82 | { 83 | super(context, attributeSet); 84 | //设置置顶 85 | setZOrderOnTop(true); 86 | mSurfaceHolder = this.getHolder(); 87 | mSurfaceHolder.addCallback(this); 88 | 89 | Resources mResources = context.getResources(); 90 | mMarginValue = (int) mResources.getDimension(R.dimen.layout_spacing); 91 | mMarginTop = (int) mResources.getDimension(R.dimen.bar_chart_margin_top); 92 | mMarginBottom = (int) mResources.getDimension(R.dimen.bar_chart_margin_bottom); 93 | mTextSize = (int) mResources.getDimension(R.dimen.title_font_size); 94 | mBackgroundColor = mResources.getColor(R.color.background_color); 95 | mBdsBarChartSpacing = (int) mResources.getDimension(R.dimen.bar_chart_spacing); 96 | 97 | //设置坐标系的实线虚线画笔,配置mDashedPaint画虚线 98 | mDashedPaint = new Paint(); 99 | mDashedPaint.setColor(Color.BLACK); 100 | mDashedPaint.setAntiAlias(true); 101 | mDashedPaint.setStrokeWidth(1); 102 | mDashedPaint.setStyle(Paint.Style.STROKE); 103 | PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 1); 104 | mDashedPaint.setPathEffect(effects); 105 | // 配置solidPaint画实线 106 | mSolidPaint = new Paint(); 107 | mSolidPaint.setColor(Color.BLACK); 108 | mSolidPaint.setAntiAlias(true); 109 | mSolidPaint.setStrokeWidth(1); 110 | mSolidPaint.setStyle(Paint.Style.FILL); 111 | //设置画柱状图的画笔颜色,设置柱状图画笔属性 112 | mChartPaint = new Paint(); 113 | mChartPaint.setAntiAlias(true); 114 | mChartPaint.setStyle(Paint.Style.FILL); 115 | // 设置文本画笔属性 116 | mTextPaint = new Paint(); 117 | mTextPaint.setAntiAlias(true); 118 | mTextPaint.setTextSize(mTextSize); 119 | } 120 | 121 | @Override 122 | public void surfaceCreated(SurfaceHolder holder) 123 | { 124 | isSurfaceViewCreated = true; 125 | } 126 | 127 | @Override 128 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 129 | { 130 | isSurfaceViewCreated = true; 131 | new BdsDrawBarThread(mSurfaceHolder, mSatelliteAdapter).start(); 132 | } 133 | 134 | @Override 135 | public void surfaceDestroyed(SurfaceHolder holder) 136 | { 137 | isSurfaceViewCreated = false; 138 | } 139 | 140 | //创建BarChartCallbacks接口,用于回调,该接口实现了根据卫星信息画柱状图 141 | private BdsBarChartCallbacks mBdsBarChartCallbacks = new BdsBarChartCallbacks() 142 | { 143 | @Override 144 | public void updateBdsSnrLayoutSize(SignalFragment signalFragment) 145 | { 146 | int mSnrLayoutWidth = signalFragment.getmBdsSnrLayoutWidth(); 147 | int mSnrLayoutHeight = signalFragment.getmBdsSnrLayoutHeight(); 148 | //计算坐标系的边缘起点、终点坐标以及柱状图间隔,单位信噪比像素值 149 | mBorderLeft = mMarginValue; 150 | mBorderTop = mMarginTop + mTextSize; 151 | mBorderRight = mSnrLayoutWidth - mMarginValue; 152 | mBorderBottom = mSnrLayoutHeight - mMarginBottom - mTextSize; 153 | mLineGap = (mBorderBottom - mBorderTop) / (Constant.LINE_NUM - 1); 154 | mBarGap = (mBorderRight - mBorderLeft) / Constant.BAR_NUM; 155 | mSnrGap = (mBorderBottom - mBorderTop) / Constant.MAX_SNR; 156 | } 157 | 158 | @Override 159 | public void updateBdsSatelliteSrn(SatelliteAdapter satelliteAdapter) 160 | { 161 | //首先判断SurfaceView是否已建立 162 | mSatelliteAdapter = satelliteAdapter; 163 | if (isSurfaceViewCreated) 164 | { 165 | new BdsDrawBarThread(mSurfaceHolder, mSatelliteAdapter).start(); 166 | } 167 | } 168 | }; 169 | 170 | //创建一个新的线程用于在SurfaceView中绘图 171 | private class BdsDrawBarThread extends Thread 172 | { 173 | private Canvas mThreadCanvas; 174 | private SatelliteAdapter mThreadSatelliteAdapter; 175 | private SurfaceHolder mThreadHolder; 176 | 177 | public BdsDrawBarThread(SurfaceHolder surfaceHolder, SatelliteAdapter satelliteAdapter) 178 | { 179 | mThreadHolder = surfaceHolder; 180 | mThreadSatelliteAdapter = satelliteAdapter; 181 | } 182 | 183 | @Override 184 | public void run() 185 | { 186 | synchronized (mThreadHolder) 187 | { 188 | mThreadCanvas = mThreadHolder.lockCanvas(); 189 | drawBdsCoordinate(mThreadCanvas); 190 | drawBdsBarChart(mThreadSatelliteAdapter, mThreadCanvas); 191 | mThreadHolder.unlockCanvasAndPost(mThreadCanvas); 192 | } 193 | } 194 | } 195 | 196 | /** 197 | * 获取SatelliteView中的接口 198 | * 199 | * @return 200 | */ 201 | public BdsBarChartCallbacks getmBdsBarChartCallbacks() 202 | { 203 | return mBdsBarChartCallbacks; 204 | } 205 | 206 | /** 207 | * 画BDS的坐标 208 | * 209 | * @param canvas 210 | */ 211 | public void drawBdsCoordinate(Canvas canvas) 212 | { 213 | if (null != canvas) 214 | { 215 | //重新画背景 216 | canvas.drawColor(mBackgroundColor); 217 | //画坐标系,先画实线 218 | canvas.drawLine(mBorderLeft, mBorderBottom, mBorderRight, mBorderBottom, mSolidPaint); 219 | //再画虚线 220 | for (int i = 1; i < Constant.LINE_NUM; i++) 221 | { 222 | canvas.drawLine(mBorderLeft, mBorderTop + (i - 1) * mLineGap, mBorderRight, mBorderTop + (i - 1) * mLineGap, mDashedPaint); 223 | } 224 | } 225 | } 226 | 227 | /** 228 | * 画BDS的柱状图 229 | * 230 | * @param satelliteAdapter 231 | * @param canvas 232 | */ 233 | public void drawBdsBarChart(SatelliteAdapter satelliteAdapter, Canvas canvas) 234 | { 235 | if (null == satelliteAdapter || null == satelliteAdapter.getmBdsSatelliteList() || null == canvas) 236 | { 237 | return; 238 | } 239 | int mSnr = 0; 240 | int mPrn = 0; 241 | int mGpsSatelliteSize = 0; 242 | isUsedInFix = false; 243 | List mGpsSatelliteList = satelliteAdapter.getmBdsSatelliteList(); 244 | mGpsSatelliteSize = mGpsSatelliteList.size() < Constant.BAR_NUM ? mGpsSatelliteList.size() : Constant.BAR_NUM; 245 | 246 | MySatellite mGpsSatellite; 247 | for (int i = 0; i < mGpsSatelliteSize; i++) 248 | { 249 | mGpsSatellite = mGpsSatelliteList.get(i); 250 | isUsedInFix = mGpsSatellite.usedInFix(); 251 | mSnr = (int) mGpsSatellite.getSnr(); 252 | mPrn = mGpsSatellite.getPrn(); 253 | // 判断柱状图颜色 254 | if (isUsedInFix) 255 | { 256 | if (mSnr >= 40) 257 | { 258 | mChartPaint.setColor(Color.BLUE); 259 | } 260 | else if (mSnr >= 30) 261 | { 262 | mChartPaint.setColor(Color.GREEN); 263 | } 264 | else if (mSnr >= 20) 265 | { 266 | mChartPaint.setColor(Color.YELLOW); 267 | } 268 | else if (mSnr >= 10) 269 | { 270 | mChartPaint.setColor(Color.MAGENTA); 271 | } 272 | else 273 | { 274 | mChartPaint.setColor(Color.RED); 275 | } 276 | } 277 | else 278 | { 279 | mChartPaint.setColor(Color.GRAY); 280 | } 281 | // 卫星号 282 | canvas.drawText(String.valueOf(mPrn), mBorderLeft + mBarGap * i, mBorderBottom + mTextSize, mTextPaint); 283 | // 柱状图 284 | canvas.drawRect(mBorderLeft + mBarGap * i, mBorderBottom - mSnr * mSnrGap, mBorderLeft + mBarGap * (i + 1) - mBdsBarChartSpacing, mBorderBottom, mChartPaint); 285 | // 信噪比值 286 | canvas.drawText(String.valueOf(mSnr), mBorderLeft + mBarGap * i, mBorderBottom - (mSnr * mSnrGap), mTextPaint); 287 | } 288 | } 289 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/BdsBarChartCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import com.tonker.gnss.fragment.SignalFragment; 4 | import com.tonker.gnss.location.SatelliteAdapter; 5 | 6 | /** 7 | * 定义一个回调接口,该接口中提供方法来获取SrnLayout的尺寸,并更新BDS卫星信噪比的柱状图 8 | * @author newtonker 9 | * @date 2014-06-18 10 | */ 11 | public interface BdsBarChartCallbacks 12 | { 13 | /** 14 | * 获取SrnLayout的尺寸(宽和高) 15 | * @param signalFragment 16 | */ 17 | void updateBdsSnrLayoutSize(SignalFragment signalFragment); 18 | 19 | /** 20 | * 获取可见卫星的信噪比并绘制信噪比柱状图 21 | * @param satelliteAdapter 22 | */ 23 | void updateBdsSatelliteSrn(SatelliteAdapter satelliteAdapter); 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/SatelliteView.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import java.util.List; 4 | 5 | import com.tonker.gnss.R; 6 | import com.tonker.gnss.fragment.OrientationFragment; 7 | import com.tonker.gnss.location.MySatellite; 8 | import com.tonker.gnss.location.SatelliteAdapter; 9 | 10 | import android.content.Context; 11 | import android.content.res.Resources; 12 | import android.graphics.Bitmap; 13 | import android.graphics.BitmapFactory; 14 | import android.graphics.Canvas; 15 | import android.graphics.Color; 16 | import android.graphics.Paint; 17 | import android.graphics.Paint.Align; 18 | import android.graphics.RectF; 19 | import android.util.AttributeSet; 20 | import android.view.SurfaceHolder; 21 | import android.view.SurfaceHolder.Callback; 22 | import android.view.SurfaceView; 23 | 24 | public class SatelliteView extends SurfaceView implements Callback 25 | { 26 | //定义边界距离 27 | private int mMarginValue; 28 | 29 | //定义圆盘的起点和终点 30 | private int startX; 31 | private int startY; 32 | private int endX; 33 | private int endY; 34 | 35 | private SurfaceHolder mSurfaceHolder; 36 | //设置SatelliteView创建标志位,绘制卫星时调用 37 | private boolean isSatelliteViewEnabled = false; 38 | 39 | //定义圆心和半径 40 | private int xCenter; 41 | private int yCenter; 42 | private int mRadius; 43 | 44 | //定义背景图片 45 | private Bitmap mCompassBitmap; 46 | // 设置圆盘背景所放的位置 47 | private RectF mRectF; 48 | //定义背景颜色 49 | private int mBackgroundColor; 50 | 51 | //定义获取卫星信息的一些变量 52 | //缓存SatelliteAdapter数据 53 | private SatelliteAdapter mSatelliteAdapter; 54 | //设置绘制卫星编号的画笔 55 | private Paint mTextPaint; 56 | // 设置绘制卫星颜色的画笔 57 | private Paint mSatellitePaint; 58 | //定义代表卫星的圆的半径 59 | private int mSatelliteRadius; 60 | 61 | public SatelliteView(Context context, AttributeSet attrs) 62 | { 63 | super(context, attrs); 64 | //设置置顶 65 | setZOrderOnTop(true); 66 | mSurfaceHolder = this.getHolder(); 67 | mSurfaceHolder.addCallback(this); 68 | //加载背景图片 69 | Resources mResource = context.getResources(); 70 | mCompassBitmap = BitmapFactory.decodeResource(mResource, R.drawable.tab_orientation_compass); 71 | //获取边界距离 72 | mMarginValue = (int) mResource.getDimension(R.dimen.layout_spacing); 73 | //获取卫星的半径 74 | mSatelliteRadius = (int) mResource.getDimension(R.dimen.satellite_radius); 75 | //获取背景颜色 76 | mBackgroundColor = mResource.getColor(R.color.background_color); 77 | //设置绘制卫星编号的画笔 78 | mTextPaint = new Paint(); 79 | mTextPaint.setAntiAlias(true); 80 | mTextPaint.setColor(Color.CYAN); 81 | mTextPaint.setTextSize(mResource.getDimension(R.dimen.title_font_size)); 82 | mTextPaint.setTextAlign(Align.CENTER); 83 | //设置绘制卫星颜色的画笔 84 | mSatellitePaint = new Paint(); 85 | mSatellitePaint.setAntiAlias(true); 86 | mSatellitePaint.setStyle(Paint.Style.FILL); 87 | } 88 | 89 | @Override 90 | public void surfaceCreated(SurfaceHolder holder) 91 | { 92 | isSatelliteViewEnabled = true; 93 | } 94 | 95 | @Override 96 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 97 | { 98 | isSatelliteViewEnabled = true; 99 | if (null == mRectF) 100 | { 101 | mRectF = new RectF(startX, startY, endX, endY); 102 | } 103 | new SatelliteViewThread(mSurfaceHolder, mSatelliteAdapter).start(); 104 | } 105 | 106 | @Override 107 | public void surfaceDestroyed(SurfaceHolder holder) 108 | { 109 | isSatelliteViewEnabled = false; 110 | } 111 | 112 | private SatelliteViewCallbacks mSatelliteViewCallbacks = new SatelliteViewCallbacks() 113 | { 114 | @Override 115 | public void updateSatelliteViewSize(OrientationFragment orientation) 116 | { 117 | //获取Layout边界宽和高等信息 118 | int mSatelliteViewWidth = orientation.getmSatelliteViewWidth(); 119 | int mSatelliteViewHeight = orientation.getmSatelliteViewHeight(); 120 | int mBorderLeft = mMarginValue; 121 | int mBorderRight = mSatelliteViewWidth - mMarginValue; 122 | int mBorderTop = mMarginValue * 4; 123 | int mBorderBottom = mSatelliteViewHeight - mMarginValue; 124 | 125 | int mBorderWidth = mBorderRight - mBorderLeft; 126 | int mBorderHeight = mBorderBottom - mBorderTop; 127 | int mBorderSize = (mBorderWidth < mBorderHeight) ? mBorderWidth : mBorderHeight; 128 | 129 | //确定圆心和半径 130 | xCenter = mSatelliteViewWidth / 2; 131 | yCenter = mBorderTop + mBorderSize / 2; 132 | mRadius = mBorderSize / 2; 133 | //确定绘制圆盘的边界 134 | startX = xCenter - mBorderSize / 2; 135 | startY = mBorderTop; 136 | endX = startX + mBorderSize; 137 | endY = startY + mBorderSize; 138 | } 139 | 140 | @Override 141 | public void updateSatelliteViewInfo(SatelliteAdapter satelliteAdapter) 142 | { 143 | mSatelliteAdapter = satelliteAdapter; 144 | if (isSatelliteViewEnabled) 145 | { 146 | new SatelliteViewThread(mSurfaceHolder, mSatelliteAdapter).start(); 147 | } 148 | } 149 | }; 150 | 151 | //创建一个新的线程用于在SurfaceView中绘图 152 | private class SatelliteViewThread extends Thread 153 | { 154 | private Canvas mThreadCanvas; 155 | private SatelliteAdapter mThreadSatelliteAdapter; 156 | private SurfaceHolder mThreadHolder; 157 | 158 | public SatelliteViewThread(SurfaceHolder surfaceHolder, SatelliteAdapter satelliteAdapter) 159 | { 160 | mThreadHolder = surfaceHolder; 161 | mThreadSatelliteAdapter = satelliteAdapter; 162 | } 163 | 164 | @Override 165 | public void run() 166 | { 167 | synchronized (mThreadHolder) 168 | { 169 | mThreadCanvas = mThreadHolder.lockCanvas(); 170 | drawBackground(mThreadCanvas); 171 | drawSatelliteView(mThreadSatelliteAdapter, mThreadCanvas); 172 | mThreadHolder.unlockCanvasAndPost(mThreadCanvas); 173 | } 174 | } 175 | } 176 | 177 | /** 178 | * 获取SatelliteView中的接口 179 | * 180 | * @return 181 | */ 182 | public SatelliteViewCallbacks getmSatelliteViewCallbacks() 183 | { 184 | return mSatelliteViewCallbacks; 185 | } 186 | 187 | /** 188 | * 绘制圆盘背景 189 | * 190 | * @param canvas 191 | */ 192 | public void drawBackground(Canvas canvas) 193 | { 194 | if (null != canvas) 195 | { 196 | canvas.drawColor(mBackgroundColor); 197 | canvas.drawBitmap(mCompassBitmap, null, mRectF, null); 198 | } 199 | } 200 | 201 | /** 202 | * 绘制所获取的卫星 203 | * 204 | * @param satelliteAdapter 205 | * @param canvas 206 | */ 207 | public void drawSatelliteView(SatelliteAdapter satelliteAdapter, Canvas canvas) 208 | { 209 | if (null != satelliteAdapter && null != canvas) 210 | { 211 | //初始化信噪比和卫星号 212 | int mSnr = 0; 213 | int mPrn = 0; 214 | //方位角 215 | float mAzimuth = 0.0f; 216 | //仰角(高度角) 217 | float mElevation = 0.0f; 218 | boolean isUsedInFix = false; 219 | int mSatelliteListSize = 0; 220 | List mSatelliteList = satelliteAdapter.getmSatelliteList(); 221 | mSatelliteListSize = mSatelliteList.size(); 222 | 223 | MySatellite mGpsSatellite; 224 | for (int i = 0; i < mSatelliteListSize; i++) 225 | { 226 | mGpsSatellite = mSatelliteList.get(i); 227 | isUsedInFix = mGpsSatellite.usedInFix(); 228 | mSnr = (int) mGpsSatellite.getSnr(); 229 | mPrn = mGpsSatellite.getPrn(); 230 | mAzimuth = mGpsSatellite.getAzimuth(); 231 | mElevation = mGpsSatellite.getElevation(); 232 | String mSystem = mGpsSatellite.getSystem(); 233 | 234 | // 判断代表卫星圆圈内的填充颜色 235 | if (isUsedInFix) 236 | { 237 | if (mSnr > 40) 238 | { 239 | mSatellitePaint.setColor(Color.BLUE); 240 | } 241 | else if (mSnr > 30) 242 | { 243 | mSatellitePaint.setColor(Color.GREEN); 244 | } 245 | else if (mSnr > 20) 246 | { 247 | mSatellitePaint.setColor(Color.YELLOW); 248 | } 249 | else if (mSnr > 10) 250 | { 251 | mSatellitePaint.setColor(Color.MAGENTA); 252 | } 253 | else 254 | { 255 | mSatellitePaint.setColor(Color.RED); 256 | } 257 | } 258 | else 259 | { 260 | mSatellitePaint.setColor(Color.GRAY); 261 | } 262 | //获取代表卫星的圆距圆心的距离 263 | int x = (int) (xCenter + ((mRadius * (90 - mElevation) * Math.sin(Math.PI * mAzimuth / 180) / 90))); 264 | int y = (int) (yCenter - ((mRadius * (90 - mElevation) * Math.cos(Math.PI * mAzimuth / 180) / 90))); 265 | if (mSystem.equals("gps")) 266 | { 267 | canvas.drawCircle(x, y, mSatelliteRadius, mSatellitePaint); 268 | } 269 | else 270 | { 271 | canvas.drawRect(x - mSatelliteRadius, y - mSatelliteRadius, x + mSatelliteRadius, y + mSatelliteRadius, mSatellitePaint); 272 | } 273 | //代表卫星号的文字 274 | canvas.drawText(String.valueOf(mPrn), x + mSatelliteRadius * 1.5f, y + mSatelliteRadius * 1.5f, mTextPaint); 275 | } 276 | } 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/SatelliteViewCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import com.tonker.gnss.fragment.OrientationFragment; 4 | import com.tonker.gnss.location.SatelliteAdapter; 5 | 6 | /** 7 | * 这一类在绘制卫星方位时用于回调,提供两个方法 8 | * @author newtonker 9 | * @date 2014-06-19 10 | */ 11 | public interface SatelliteViewCallbacks 12 | { 13 | /** 14 | * 获取所在Layout的宽和高 15 | * @param orientation 16 | */ 17 | void updateSatelliteViewSize(OrientationFragment orientation); 18 | 19 | /** 20 | * 更新卫星方位图 21 | * @param satelliteAdapter 存放卫星信噪比,卫星号和方位信息 22 | */ 23 | void updateSatelliteViewInfo(SatelliteAdapter satelliteAdapter); 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/SignalScaleBar.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import com.tonker.gnss.R; 4 | import com.tonker.gnss.constant.Constant; 5 | import com.tonker.gnss.fragment.OrientationFragment; 6 | 7 | import android.content.Context; 8 | import android.content.res.Resources; 9 | import android.graphics.Canvas; 10 | import android.graphics.Color; 11 | import android.graphics.Paint; 12 | import android.util.AttributeSet; 13 | import android.view.SurfaceHolder; 14 | import android.view.SurfaceView; 15 | import android.view.SurfaceHolder.Callback; 16 | 17 | /** 18 | * 这个类用来画信号强度分布图 19 | * 20 | * @author newtonker 21 | * @date 2014-06-19 22 | */ 23 | public class SignalScaleBar extends SurfaceView implements Callback 24 | { 25 | //定义距边界的值 26 | private int mMarginValue; 27 | //设置字体大小 28 | private int mTextSize; 29 | //设置背景颜色 30 | private int mBackgroundColor; 31 | //设置柱状图左边距边界的距离 32 | private int mBarLeftToBorder; 33 | //设置柱状图右边距边界的距离 34 | private int mBarRightToBorder; 35 | 36 | //设置信号强度分布图的宽和高 37 | private int mScaleGap; 38 | private int mBorderTop; 39 | private int mBarGap; 40 | private int mBarTop; 41 | private int mBarBottom; 42 | private int mBarLeft; 43 | private int mBarRight; 44 | 45 | //定义柱条画笔的颜色和字体画笔的颜色 46 | private Paint mBarPaint; 47 | private Paint mTextPaint; 48 | 49 | public SignalScaleBar(Context context) 50 | { 51 | super(context); 52 | } 53 | 54 | public SignalScaleBar(Context context, AttributeSet attributeSet) 55 | { 56 | super(context, attributeSet); 57 | //设置置顶 58 | setZOrderOnTop(true); 59 | SurfaceHolder mSurfaceHolder = this.getHolder(); 60 | mSurfaceHolder.addCallback(this); 61 | // 获取资源 62 | Resources mResources = context.getResources(); 63 | mMarginValue = (int) mResources.getDimension(R.dimen.layout_spacing); 64 | mTextSize = (int) mResources.getDimension(R.dimen.title_font_size); 65 | mBackgroundColor = mResources.getColor(R.color.background_color); 66 | mBarLeftToBorder = (int) mResources.getDimension(R.dimen.bar_left_to_border); 67 | mBarRightToBorder = (int) mResources.getDimension(R.dimen.bar_right_to_border); 68 | // 设置画柱状条及文字的画笔属性 69 | mBarPaint = new Paint(); 70 | mBarPaint.setAntiAlias(true); 71 | mBarPaint.setStrokeWidth(1); 72 | mBarPaint.setStyle(Paint.Style.FILL); 73 | 74 | mTextPaint = new Paint(); 75 | mTextPaint.setAntiAlias(true); 76 | mTextPaint.setStrokeWidth(1); 77 | mTextPaint.setColor(Color.BLACK); 78 | mTextPaint.setTextSize(mTextSize); 79 | } 80 | 81 | @Override 82 | public void surfaceCreated(SurfaceHolder holder) 83 | { 84 | } 85 | 86 | @Override 87 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 88 | { 89 | new ScaleBarThread(holder).start(); 90 | } 91 | 92 | @Override 93 | public void surfaceDestroyed(SurfaceHolder holder) 94 | { 95 | } 96 | 97 | //创建一个新的线程,用于在SurfaceView中绘图 98 | private class ScaleBarThread extends Thread 99 | { 100 | private Canvas mThreadCanvas; 101 | private SurfaceHolder mThreadHolder; 102 | 103 | public ScaleBarThread(SurfaceHolder surfaceHolder) 104 | { 105 | mThreadHolder = surfaceHolder; 106 | } 107 | 108 | @Override 109 | public void run() 110 | { 111 | synchronized (mThreadHolder) 112 | { 113 | mThreadCanvas = mThreadHolder.lockCanvas(); 114 | drawScaleBar(mThreadCanvas); 115 | mThreadHolder.unlockCanvasAndPost(mThreadCanvas); 116 | } 117 | } 118 | } 119 | 120 | private SignalScaleBarCallbacks mSignalScaleBarCallbacks = new SignalScaleBarCallbacks() 121 | { 122 | @Override 123 | public void updateScaleLayoutSize(OrientationFragment orientationFragment) 124 | { 125 | int mScaleLayoutWidth = orientationFragment.getmScaleLayoutWidth(); 126 | int mScaleLayoutHeight = orientationFragment.getmScaleLayoutHeight(); 127 | mBorderTop = mMarginValue; 128 | int mBorderBottom = mScaleLayoutHeight - mMarginValue; 129 | int mBorderLeft = mMarginValue; 130 | int mBorderRight = mScaleLayoutWidth - mMarginValue; 131 | //纵向上分成6格 132 | mScaleGap = (mBorderBottom - mBorderTop) / Constant.SCALE_NUM; 133 | mBarTop = mBorderTop + mScaleGap; 134 | //柱条占两格 135 | mBarBottom = mBorderTop + mScaleGap * 3; 136 | mBarLeft = mBorderLeft + mBarLeftToBorder + mTextSize; 137 | mBarRight = mBorderRight - mBarRightToBorder; 138 | mBarGap = (mBarRight - mBarLeft) / Constant.SCALE_BAR_NUM; 139 | } 140 | }; 141 | 142 | public void drawScaleBar(Canvas canvas) 143 | { 144 | canvas.drawColor(mBackgroundColor); 145 | //设置条的标题 146 | canvas.drawText("信号", mBarLeft - mTextSize * 2, mBorderTop + mBarGap, mTextPaint); 147 | //设置00条 148 | mBarPaint.setColor(Color.RED); 149 | canvas.drawRect(mBarLeft, mBarTop, mBarLeft + mBarGap, mBarBottom, mBarPaint); 150 | canvas.drawText("00", mBarLeft, mBarBottom + mScaleGap * Constant.FONT_START, mTextPaint); 151 | //设置10条 152 | mBarPaint.setColor(Color.MAGENTA); 153 | canvas.drawRect(mBarLeft + mBarGap, mBarTop, mBarLeft + 2 * mBarGap, mBarBottom, mBarPaint); 154 | canvas.drawText("10", mBarLeft + mBarGap, mBarBottom + mScaleGap * Constant.FONT_START, mTextPaint); 155 | //设置20条 156 | mBarPaint.setColor(Color.YELLOW); 157 | canvas.drawRect(mBarLeft + 2 * mBarGap, mBarTop, mBarLeft + 3 * mBarGap, mBarBottom, mBarPaint); 158 | canvas.drawText("20", mBarLeft + 2 * mBarGap, mBarBottom + mScaleGap * Constant.FONT_START, mTextPaint); 159 | //设置30条 160 | mBarPaint.setColor(Color.GREEN); 161 | canvas.drawRect(mBarLeft + 3 * mBarGap, mBarTop, mBarLeft + 4 * mBarGap, mBarBottom, mBarPaint); 162 | canvas.drawText("30", mBarLeft + 3 * mBarGap, mBarBottom + mScaleGap * Constant.FONT_START, mTextPaint); 163 | //设置40条 164 | mBarPaint.setColor(Color.BLUE); 165 | canvas.drawRect(mBarLeft + 4 * mBarGap, mBarTop, mBarRight, mBarBottom, mBarPaint); 166 | canvas.drawText("40", mBarLeft + 4 * mBarGap, mBarBottom + mScaleGap * Constant.FONT_START, mTextPaint); 167 | //设置终点值 168 | canvas.drawText("99", mBarRight - mTextSize, mBarBottom + mScaleGap * Constant.FONT_START, mTextPaint); 169 | } 170 | 171 | /** 172 | * 获取当前类的接口 173 | * 174 | * @return 175 | */ 176 | public SignalScaleBarCallbacks getmSignalScaleBarCallbacks() 177 | { 178 | return mSignalScaleBarCallbacks; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/graphics/SignalScaleBarCallbacks.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.graphics; 2 | 3 | import com.tonker.gnss.fragment.OrientationFragment; 4 | 5 | public interface SignalScaleBarCallbacks 6 | { 7 | /** 8 | * 获取要画的颜色柱状图的宽和高 9 | * @param orientationFragment 10 | */ 11 | void updateScaleLayoutSize(OrientationFragment orientationFragment); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/location/LocationAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.location; 2 | 3 | import com.tonker.gnss.constant.Constant; 4 | import com.tonker.gnss.fragment.*; 5 | import android.location.GpsStatus; 6 | import android.location.LocationListener; 7 | import android.location.LocationManager; 8 | import android.location.Location; 9 | import android.location.LocationProvider; 10 | import android.os.Bundle; 11 | 12 | /** 13 | * 这一个类主要实现了GNSS导航参数的设置,位置变化和状态变化的侦听 14 | * @author newtonker 15 | * @date 2014-06-18 16 | */ 17 | public class LocationAdapter 18 | { 19 | private LocationManager mLocationManager; 20 | private SatelliteAdapter mSatelliteAdapter; 21 | 22 | //四个Fragment对应的回调接口实例 23 | private TimeCallbacks mTimeCallbacks; 24 | private SignalCallbacks mSignalCallbacks; 25 | private OrientationCallbacks mOrientationCallbacks; 26 | private MessageCallbacks mMessageCallbacks; 27 | 28 | //设置GNSS定位状态标志位 29 | private boolean isFixed = false; 30 | private int times = 0; 31 | //设置GNSS开关状态标识位 32 | private boolean isGnssEnabled = false; 33 | //用于存储和判断Nmea的语句 34 | private StringBuilder mBuilder; 35 | 36 | //Constructor 37 | public LocationAdapter(SignalFragment signalFragment,OrientationFragment orientationFragment, 38 | TimeFragment timeFragment,MessageFragment messageFragment, LocationManager locationManager, 39 | Location location) 40 | { 41 | this.mLocationManager = locationManager; 42 | this.mSatelliteAdapter = new SatelliteAdapter(locationManager); 43 | 44 | this.mSignalCallbacks = signalFragment.getSignalCallbacks(); 45 | this.mOrientationCallbacks = orientationFragment.getOrientationCallbacks(); 46 | this.mTimeCallbacks = timeFragment.getTimeCallbacks(); 47 | this.mMessageCallbacks = messageFragment.getMessageCallbacks(); 48 | 49 | // 检测GNSS开关的状态 50 | isGnssEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); 51 | //初始化NMEA语句存储变量 52 | mBuilder = new StringBuilder(); 53 | //更新界面 54 | updateLocationView(location, isGnssEnabled); 55 | updateStatusView(isGnssEnabled); 56 | // 对LocationManager增加GNSS状态监听状态 57 | locationManager.addGpsStatusListener(mListener); 58 | locationManager.addNmeaListener(mNmeaListener); 59 | // 增加GNSS位置监听 60 | locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, mLocationListener); 61 | 62 | } 63 | 64 | // (属性)位置监听器 65 | private LocationListener mLocationListener = new LocationListener() 66 | { 67 | // 位置信息变化时触发 68 | @Override 69 | public void onLocationChanged(Location location) 70 | { 71 | isFixed = true; 72 | times = 0; 73 | updateFixStatus(isGnssEnabled, Constant.FIX_SUCCEED); 74 | updateLocationView(location, isGnssEnabled); 75 | } 76 | 77 | // LocationProvider状态变化时触发 78 | @Override 79 | public void onStatusChanged(String provider, int status, Bundle extras) 80 | { 81 | switch (status) 82 | { 83 | // LocationProvider状态为可见时 84 | case LocationProvider.AVAILABLE: break; 85 | // LocationProvider状态为服务区之外时 86 | case LocationProvider.OUT_OF_SERVICE: break; 87 | // LocationProvider状态为暂停服务时 88 | case LocationProvider.TEMPORARILY_UNAVAILABLE: break; 89 | } 90 | } 91 | // GNSS开启时触发 92 | @Override 93 | public void onProviderEnabled(String provider) 94 | { 95 | Location location = mLocationManager.getLastKnownLocation(provider); 96 | //GNSS开关标志位置位 97 | isGnssEnabled = true; 98 | updateLocationView(location, isGnssEnabled); 99 | } 100 | // GNSS禁用时触发 101 | @Override 102 | public void onProviderDisabled(String provider) 103 | { 104 | //GNSS开关标志位清零 105 | isGnssEnabled = false; 106 | updateLocationView(null, isGnssEnabled); 107 | updateStatusView(isGnssEnabled); 108 | } 109 | }; 110 | 111 | // (属性)状态监听器 112 | GpsStatus.Listener mListener = new GpsStatus.Listener() 113 | { 114 | @Override 115 | public void onGpsStatusChanged(int event) 116 | { 117 | switch (event) 118 | { 119 | // 第一次定位 120 | case GpsStatus.GPS_EVENT_FIRST_FIX: 121 | updateFixStatus(isGnssEnabled, Constant.FIX_SUCCEED); 122 | break; 123 | // 卫星状态改变 124 | case GpsStatus.GPS_EVENT_SATELLITE_STATUS: 125 | if(!isFixed) 126 | { 127 | updateFixStatus(isGnssEnabled, Constant.FIX_BEGIN); 128 | } 129 | mSatelliteAdapter.setSatelliteAdapter(); 130 | updateStatusView(isGnssEnabled); 131 | times++; 132 | if(2 == times) 133 | { 134 | isFixed = false; 135 | times = 0; 136 | } 137 | break; 138 | // 定位启动 139 | case GpsStatus.GPS_EVENT_STARTED: 140 | updateFixStatus(isGnssEnabled, Constant.FIX_BEGIN); 141 | break; 142 | // 定位结束 143 | case GpsStatus.GPS_EVENT_STOPPED: 144 | updateFixStatus(isGnssEnabled, Constant.FIX_STOP); 145 | break; 146 | } 147 | } 148 | }; 149 | 150 | 151 | //增加对NMEA0183协议的侦听 152 | GpsStatus.NmeaListener mNmeaListener = new GpsStatus.NmeaListener() 153 | { 154 | @Override 155 | public void onNmeaReceived(long timestamp, String nmea) 156 | { 157 | int index = nmea.indexOf("$"); 158 | if(-1 == index) 159 | { 160 | mBuilder.append(nmea); 161 | } 162 | else 163 | { 164 | if(0 == index) 165 | { 166 | mMessageCallbacks.updateMessageViewInfo(timestamp, mBuilder.toString(), isGnssEnabled); 167 | } 168 | else 169 | { 170 | mBuilder.append(nmea.substring(0, index - 1)); 171 | int index1 = mBuilder.toString().indexOf('\n'); 172 | if(-1 == index1) 173 | { 174 | mBuilder.append("\n"); 175 | } 176 | mMessageCallbacks.updateMessageViewInfo(timestamp, mBuilder.toString(), isGnssEnabled); 177 | } 178 | mBuilder.delete(0, mBuilder.length()); 179 | mBuilder.append(nmea.substring(index)); 180 | } 181 | } 182 | }; 183 | 184 | /** 185 | * 更新卫星信噪比、可见卫星数、已连接卫星数等界面的方法 186 | * 卫星状态改变时调用 187 | * @param isGnssEnabled 188 | */ 189 | public void updateStatusView(boolean isGnssEnabled) 190 | { 191 | // 若SignalFragment已创建 192 | if (null != mSignalCallbacks) 193 | { 194 | mSignalCallbacks.updateSignalViewSnrInfo(mSatelliteAdapter, isGnssEnabled); 195 | } 196 | // 若OrientationFragment已创建 197 | if (null != mOrientationCallbacks) 198 | { 199 | mOrientationCallbacks.updateOrientationViewInfo(mSatelliteAdapter, isGnssEnabled); 200 | } 201 | } 202 | 203 | /** 204 | * 更新定位状态信息 205 | * @param isGnssEnabled 206 | * @param s 207 | */ 208 | public void updateFixStatus(boolean isGnssEnabled, String s) 209 | { 210 | // 若SignalFragment已创建 211 | if (null != mSignalCallbacks) 212 | { 213 | mSignalCallbacks.updateSignalViewFixStatus(isGnssEnabled, s); 214 | } 215 | } 216 | 217 | /** 218 | * 更新定位后的经纬度、时间、精确度等信息 219 | * 主要用在GNSS位置侦听中,当位置变化时调用 220 | * @param location 221 | * @param isGnassEnabled 222 | */ 223 | public void updateLocationView(Location location, boolean isGnassEnabled) 224 | { 225 | // 若SignalFragment已创建 226 | if (null != mSignalCallbacks) 227 | { 228 | mSignalCallbacks.updateSignalViewSwitch(isGnssEnabled); 229 | } 230 | // 若OrientationFragment已创建 231 | if (null != mOrientationCallbacks) 232 | { 233 | mOrientationCallbacks.updateOrientationViewLocationInfo(isGnassEnabled); 234 | } 235 | // 若TimeFragment已创建 236 | if (null != mTimeCallbacks) 237 | { 238 | mTimeCallbacks.updateTimeViewInfo(location, isGnssEnabled); 239 | } 240 | } 241 | 242 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/location/MySatellite.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.location; 2 | 3 | 4 | 5 | public class MySatellite 6 | { 7 | private int mPrn; 8 | private float mSnr; 9 | private float mElev; 10 | private float mAzim; 11 | private boolean mIsUsed; 12 | 13 | public void setmIsUsed(boolean mIsUsed) 14 | { 15 | this.mIsUsed = mIsUsed; 16 | } 17 | 18 | private String mSystem; 19 | 20 | public void setmSystem(String mSystem) 21 | { 22 | this.mSystem = mSystem; 23 | } 24 | 25 | public MySatellite() 26 | { 27 | } 28 | public MySatellite(int prn, float snr, float elev, float azim) 29 | { 30 | this.mPrn = prn; 31 | this.mSnr = snr; 32 | this.mElev = elev; 33 | this.mAzim = azim; 34 | // this.mIsUsed = isUsed; 35 | // this.mSystem = sys; 36 | } 37 | 38 | public int getPrn() 39 | { 40 | return mPrn; 41 | } 42 | 43 | public float getSnr() 44 | { 45 | return mSnr; 46 | } 47 | 48 | public float getElevation() 49 | { 50 | return mElev; 51 | } 52 | 53 | public float getAzimuth() 54 | { 55 | return mAzim; 56 | } 57 | 58 | public boolean usedInFix() 59 | { 60 | return mIsUsed; 61 | } 62 | 63 | public String getSystem() 64 | { 65 | return mSystem; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/tonker/gnss/location/SatelliteAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tonker.gnss.location; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import android.location.GpsSatellite; 8 | import android.location.GpsStatus; 9 | import android.location.LocationManager; 10 | 11 | /** 12 | * 这一个类主要实现了获取可见卫星数,已连接卫星数,以及信噪比和方位等信息 13 | * 14 | * @author newtonker 15 | * @date 2014-06-17 16 | */ 17 | public class SatelliteAdapter 18 | { 19 | private LocationManager mLocationManager; 20 | 21 | //获取的时间直接转换成以秒为单位 22 | private int mFirstFixTime; 23 | private int mVisiable; 24 | private int mConnect; 25 | private int mGpsVisiable; 26 | 27 | private int mGpsConnect; 28 | private int mBdsVisiable; 29 | private int mBdsConnect; 30 | 31 | //用于存储所有可见卫星的信息列表 32 | private List mSatelliteList; 33 | //用于存储GPS可见卫星的信息列表 34 | private List mGpsSatelliteList; 35 | //用于存储BDS可见卫星的信息列表 36 | private List mBdsSatelliteList; 37 | 38 | public SatelliteAdapter(LocationManager locationManager) 39 | { 40 | this.mLocationManager = locationManager; 41 | } 42 | 43 | public void setSatelliteAdapter() 44 | { 45 | // 实例化,获取当前GPS状态 46 | GpsStatus mGpsStatus = mLocationManager.getGpsStatus(null); 47 | // 获取默认最大卫星数 48 | int maxSatellites = mGpsStatus.getMaxSatellites(); 49 | // 获取第一次定位时间(启动到第一次定位) 50 | mFirstFixTime = mGpsStatus.getTimeToFirstFix() / 1000; 51 | // 获取卫星信息列表 52 | Iterator mIterator = mGpsStatus.getSatellites().iterator(); 53 | //初始化存储卫星列表 54 | mSatelliteList = new ArrayList(); 55 | // 通过遍历重新整理为ArrayList 56 | mGpsSatelliteList = new ArrayList(); 57 | // 初始化BDS存储卫星列表 58 | mBdsSatelliteList = new ArrayList(); 59 | // 初始化可见卫星数、已连接卫星数 60 | mVisiable = 0; 61 | mConnect = 0; 62 | mGpsVisiable = 0; 63 | mGpsConnect = 0; 64 | mBdsVisiable = 0; 65 | mBdsConnect = 0; 66 | // 总共搜索到的卫星数 67 | GpsSatellite mGpsSatellite; 68 | while (mIterator.hasNext() && mVisiable <= maxSatellites) 69 | { 70 | mGpsSatellite = mIterator.next(); 71 | float mFakeElevation = mGpsSatellite.getElevation(); 72 | //判断是否用了中科微驱动 73 | if (mFakeElevation > 90) 74 | { 75 | //获取真实prn 76 | int mFakeElev = (int) mFakeElevation; 77 | int mPrn = mFakeElev / 10000; 78 | mFakeElev -= mPrn * 10000; 79 | int mSys = mFakeElev / 1000; 80 | mFakeElev -= mSys * 1000; 81 | int mUsed = mFakeElev / 100; 82 | float mRealElev = mFakeElev % 100; 83 | MySatellite mMySatellite = new MySatellite(mPrn, mGpsSatellite.getSnr(), mRealElev, mGpsSatellite.getAzimuth()); 84 | mVisiable++; 85 | if (0 == mSys) 86 | { 87 | mGpsVisiable++; 88 | mMySatellite.setmSystem("gps"); 89 | if (1 == mUsed) 90 | { 91 | mConnect++; 92 | mGpsConnect++; 93 | mMySatellite.setmIsUsed(true); 94 | } 95 | else 96 | { 97 | mMySatellite.setmIsUsed(false); 98 | } 99 | mGpsSatelliteList.add(mMySatellite); 100 | } 101 | else 102 | { 103 | mBdsVisiable++; 104 | mMySatellite.setmSystem("bds"); 105 | if (1 == mUsed) 106 | { 107 | mConnect++; 108 | mBdsConnect++; 109 | mMySatellite.setmIsUsed(true); 110 | } 111 | else 112 | { 113 | mMySatellite.setmIsUsed(false); 114 | } 115 | mBdsSatelliteList.add(mMySatellite); 116 | } 117 | mSatelliteList.add(mMySatellite); 118 | } 119 | else 120 | { 121 | int mPrn = mGpsSatellite.getPrn(); 122 | MySatellite mMySatellite = new MySatellite(mPrn, mGpsSatellite.getSnr(), mFakeElevation, mGpsSatellite.getAzimuth()); 123 | mVisiable++; 124 | mGpsVisiable++; 125 | mMySatellite.setmSystem("gps"); 126 | if (mGpsSatellite.usedInFix()) 127 | { 128 | mConnect++; 129 | mGpsConnect++; 130 | mMySatellite.setmIsUsed(true); 131 | } 132 | else 133 | { 134 | mMySatellite.setmIsUsed(false); 135 | } 136 | mGpsSatelliteList.add(mMySatellite); 137 | mSatelliteList.add(mMySatellite); 138 | } 139 | } 140 | } 141 | 142 | /** 143 | * 获取第一次定位时长 144 | * 145 | * @return 146 | */ 147 | public int getmFirstFixTime() 148 | { 149 | return mFirstFixTime; 150 | } 151 | 152 | /** 153 | * 获取可见卫星数 154 | * 155 | * @return 156 | */ 157 | public int getmVisiable() 158 | { 159 | return mVisiable; 160 | } 161 | 162 | /** 163 | * 获取已连接卫星数 164 | * 165 | * @return 166 | */ 167 | public int getmConnect() 168 | { 169 | return mConnect; 170 | } 171 | 172 | public int getmGpsVisiable() 173 | { 174 | return mGpsVisiable; 175 | } 176 | 177 | public int getmGpsConnect() 178 | { 179 | return mGpsConnect; 180 | } 181 | 182 | public int getmBdsVisiable() 183 | { 184 | return mBdsVisiable; 185 | } 186 | 187 | public int getmBdsConnect() 188 | { 189 | return mBdsConnect; 190 | } 191 | 192 | /** 193 | * 获取存放所有Satellite列表对象 194 | * 195 | * @return 196 | */ 197 | public List getmSatelliteList() 198 | { 199 | return mSatelliteList; 200 | } 201 | 202 | /** 203 | * 获取存放GpsSatellite的列表对象 204 | * 205 | * @return 206 | */ 207 | public List getmGpsSatelliteList() 208 | { 209 | return mGpsSatelliteList; 210 | } 211 | 212 | /** 213 | * 获取存放BdsSatellite的列表对象 214 | * 215 | * @return 216 | */ 217 | public List getmBdsSatelliteList() 218 | { 219 | return mBdsSatelliteList; 220 | } 221 | 222 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/feedback_title.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/feedback_title.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_3gp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_3gp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_apk.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_bmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_bmp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_cab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_cab.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_chm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_chm.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_doc.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_folder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_folder.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_folder_up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_folder_up.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_jpg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_jpg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_mp3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_mp3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_mp4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_mp4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_ppt.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_root.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_root.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_swf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_swf.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_tif.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_tif.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_txt.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_unknown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_unknown.gif -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_wav.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_wav.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/filedialog_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/filedialog_zip.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/gnss_assist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/gnss_assist.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/menu_exit_alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/menu_exit_alert.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/tab_message.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_orientation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/tab_orientation.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_orientation_compass.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/tab_orientation_compass.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/tab_select.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_select_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/tab_select_down.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_signal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/tab_signal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tab_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/tab_time.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/title_back_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/title_back_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/title_back_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/title_back_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/title_next_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/title_next_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/title_next_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newtonker/GnssAssist/1529acd2c6555a970be3d9867fe519207922491a/app/src/main/res/drawable-hdpi/title_next_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 9 | 10 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_border_pressed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 9 | 10 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_buttom_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tab_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 13 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/title_back_button_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/title_next_button_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/filedialog_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 21 | 22 | 29 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 17 | 18 | 24 | 29 | 34 | 39 | 40 | 41 | 47 | 48 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab_a.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 25 | 26 | 29 | 30 | 33 | 34 | 35 | 36 | 40 | 41 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 58 | 59 | 60 | 64 | 65 | 70 | 71 | 79 | 80 | 89 | 90 | 91 | 92 | 97 | 98 | 106 | 107 | 116 | 117 | 118 | 119 | 120 | 127 | 133 | 134 | 135 | 136 | 137 | 141 | 142 | 143 | 147 | 148 | 153 | 154 | 162 | 163 | 172 | 173 | 174 | 175 | 180 | 181 | 189 | 190 | 199 | 200 | 201 | 202 | 203 | 210 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab_b.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 23 | 24 | 27 | 28 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | 56 | 57 | 60 | 61 | 64 | 65 | 68 | 69 | 70 | 71 | 72 | 82 | 83 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 98 | 99 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab_c.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 21 | 22 | 25 | 26 | 29 | 30 | 31 | 34 | 35 | 38 | 39 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 52 | 55 | 56 | 59 | 60 | 63 | 64 | 65 | 68 | 69 | 72 | 73 | 76 | 77 | 78 | 79 | 80 | 87 | 88 | 93 | 94 | 100 | 101 | 107 | 108 | 109 | 114 | 115 | 121 | 122 | 128 | 129 | 130 | 131 | 132 | 133 | 137 | 138 | 141 | 142 | 145 | 146 | 149 | 150 | 151 | 154 | 155 | 158 | 159 | 162 | 163 | 164 | 165 | 166 | 167 | 171 | 172 | 175 | 176 | 179 | 180 | 183 | 184 | 185 | 188 | 189 | 192 | 193 | 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /app/src/main/res/layout/tab_d.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | 20 | 21 | 27 | 28 | 29 | 36 | 43 | 50 | 57 | 58 | 59 | 60 | 61 | 67 |