Mohammed Khider
8 years ago
38 changed files with 2486 additions and 4 deletions
@ -0,0 +1,9 @@
|
||||
*.iml |
||||
.gradle |
||||
/local.properties |
||||
/.idea/workspace.xml |
||||
/.idea/libraries |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
.externalNativeBuild |
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<module external.linked.project.id="GNSSLogger" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4"> |
||||
<component name="FacetManager"> |
||||
<facet type="java-gradle" name="Java-Gradle"> |
||||
<configuration> |
||||
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" /> |
||||
<option name="BUILDABLE" value="false" /> |
||||
</configuration> |
||||
</facet> |
||||
</component> |
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true"> |
||||
<exclude-output /> |
||||
<content url="file://$MODULE_DIR$"> |
||||
<excludeFolder url="file://$MODULE_DIR$/.gradle" /> |
||||
</content> |
||||
<orderEntry type="inheritedJdk" /> |
||||
<orderEntry type="sourceFolder" forTests="false" /> |
||||
</component> |
||||
</module> |
@ -0,0 +1,148 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4"> |
||||
<component name="FacetManager"> |
||||
<facet type="android-gradle" name="Android-Gradle"> |
||||
<configuration> |
||||
<option name="GRADLE_PROJECT_PATH" value=":app" /> |
||||
</configuration> |
||||
</facet> |
||||
<facet type="android" name="Android"> |
||||
<configuration> |
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" /> |
||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> |
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> |
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> |
||||
<afterSyncTasks> |
||||
<task>generateDebugSources</task> |
||||
</afterSyncTasks> |
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" /> |
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> |
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> |
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" /> |
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" /> |
||||
</configuration> |
||||
</facet> |
||||
</component> |
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false"> |
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" /> |
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" /> |
||||
<exclude-output /> |
||||
<content url="file://$MODULE_DIR$"> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> |
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support.test.espresso/espresso-core/2.2.2/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support.test.espresso/espresso-idling-resource/2.2.2/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support.test/exposed-instrumentation-api-publish/0.5/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support.test/rules/0.5/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support.test/runner/0.5/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-compat/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-ui/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-core-utils/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-fragment/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-media-compat/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v13/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/24.2.1/jars" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" /> |
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" /> |
||||
</content> |
||||
<orderEntry type="jdk" jdkName="Android API 24 Platform" jdkType="Android SDK" /> |
||||
<orderEntry type="sourceFolder" forTests="false" /> |
||||
<orderEntry type="library" exported="" name="support-v4-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-compat-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="animated-vector-drawable-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-fragment-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="runner-0.5" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-idling-resource-2.2.2" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-library-1.3" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-integration-1.3" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="jsr305-2.0.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="design-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-media-compat-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-v13-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="espresso-core-2.2.2" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="exposed-instrumentation-api-publish-0.5" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-core-ui-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="recyclerview-v7-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="rules-0.5" level="project" /> |
||||
<orderEntry type="library" exported="" name="appcompat-v7-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-vector-drawable-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="javax.annotation-api-1.2" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-core-utils-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="javax.inject-1" level="project" /> |
||||
<orderEntry type="library" exported="" name="support-annotations-24.2.1" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="javawriter-2.1.1" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" /> |
||||
<orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" /> |
||||
</component> |
||||
</module> |
@ -0,0 +1,31 @@
|
||||
apply plugin: 'com.android.application' |
||||
|
||||
android { |
||||
compileSdkVersion 24 |
||||
buildToolsVersion "23.0.1" |
||||
defaultConfig { |
||||
applicationId "com.google.android.apps.location.gps.gnsslogger" |
||||
minSdkVersion 24 |
||||
targetSdkVersion 24 |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||
} |
||||
buildTypes { |
||||
release { |
||||
minifyEnabled false |
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
compile fileTree(include: ['*.jar'], dir: 'libs') |
||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { |
||||
exclude group: 'com.android.support', module: 'support-annotations' |
||||
}) |
||||
compile 'com.android.support:appcompat-v7:24.2.1' |
||||
testCompile 'junit:junit:4.12' |
||||
compile 'com.android.support:design:24.2.1' |
||||
compile 'com.android.support:support-v13:24.2.1' |
||||
} |
@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here. |
||||
# By default, the flags in this file are appended to flags specified |
||||
# in /media/build/master/prebuilts/fullsdk/linux/tools/proguard/proguard-android.txt |
||||
# You can edit the include path and order by changing the proguardFiles |
||||
# directive in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# Add any project specific keep options here: |
||||
|
||||
# If your project uses WebView with JS, uncomment the following |
||||
# and specify the fully qualified class name to the JavaScript interface |
||||
# class: |
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||
# public *; |
||||
#} |
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="com.google.android.apps.location.gps.gnsslogger" > |
||||
|
||||
<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="24" /> |
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> |
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> |
||||
<application |
||||
android:allowBackup="true" |
||||
android:icon="@drawable/ic_launcher" |
||||
android:label="@string/app_name" |
||||
android:theme="@style/AppTheme" > |
||||
<activity |
||||
android:name="com.google.android.apps.location.gps.gnsslogger.MainActivity" |
||||
android:screenOrientation="portrait" |
||||
android:label="@string/app_name" > |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
</application> |
||||
</manifest> |
@ -0,0 +1,401 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.location.GnssClock; |
||||
import android.location.GnssMeasurement; |
||||
import android.location.GnssMeasurementsEvent; |
||||
import android.location.GnssNavigationMessage; |
||||
import android.location.GnssStatus; |
||||
import android.location.Location; |
||||
import android.location.LocationManager; |
||||
import android.net.Uri; |
||||
import android.os.Bundle; |
||||
import android.os.Environment; |
||||
import android.os.SystemClock; |
||||
import android.util.Log; |
||||
import android.widget.Toast; |
||||
import com.google.android.apps.location.gps.gnsslogger.LoggerFragment.UIFragmentComponent; |
||||
import java.io.BufferedWriter; |
||||
import java.io.File; |
||||
import java.io.FileFilter; |
||||
import java.io.FileWriter; |
||||
import java.io.IOException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Arrays; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
|
||||
/** |
||||
* A GNSS logger to store information to a file. |
||||
*/ |
||||
public class FileLogger implements GnssListener { |
||||
|
||||
private static final String TAG = "FileLogger"; |
||||
private static final String FILE_PREFIX = "pseudoranges"; |
||||
private static final String ERROR_WRITING_FILE = "Problem writing to file."; |
||||
private static final String COMMENT_START = "# "; |
||||
private static final char RECORD_DELIMITER = ','; |
||||
private static final String VERSION_TAG = "Version: "; |
||||
private static final String FILE_VERSION = "1.4.0.0, Platform: N"; |
||||
|
||||
private static final int MAX_FILES_STORED = 100; |
||||
private static final int MINIMUM_USABLE_FILE_SIZE_BYTES = 1000; |
||||
|
||||
private final Context mContext; |
||||
|
||||
private final Object mFileLock = new Object(); |
||||
private BufferedWriter mFileWriter; |
||||
private File mFile; |
||||
|
||||
private UIFragmentComponent mUiComponent; |
||||
|
||||
public synchronized UIFragmentComponent getUiComponent() { |
||||
return mUiComponent; |
||||
} |
||||
|
||||
public synchronized void setUiComponent(UIFragmentComponent value) { |
||||
mUiComponent = value; |
||||
} |
||||
|
||||
public FileLogger(Context context) { |
||||
this.mContext = context; |
||||
} |
||||
|
||||
/** |
||||
* Start a new file logging process. |
||||
*/ |
||||
public void startNewLog() { |
||||
synchronized (mFileLock) { |
||||
File baseDirectory; |
||||
String state = Environment.getExternalStorageState(); |
||||
if (Environment.MEDIA_MOUNTED.equals(state)) { |
||||
baseDirectory = new File(Environment.getExternalStorageDirectory(), FILE_PREFIX); |
||||
baseDirectory.mkdirs(); |
||||
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { |
||||
logError("Cannot write to external storage."); |
||||
return; |
||||
} else { |
||||
logError("Cannot read external storage."); |
||||
return; |
||||
} |
||||
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyy_MM_dd_HH_mm_ss"); |
||||
Date now = new Date(); |
||||
String fileName = String.format("%s_log_%s.txt", FILE_PREFIX, formatter.format(now)); |
||||
File currentFile = new File(baseDirectory, fileName); |
||||
String currentFilePath = currentFile.getAbsolutePath(); |
||||
BufferedWriter currentFileWriter; |
||||
try { |
||||
currentFileWriter = new BufferedWriter(new FileWriter(currentFile)); |
||||
} catch (IOException e) { |
||||
logException("Could not open file: " + currentFilePath, e); |
||||
return; |
||||
} |
||||
|
||||
// initialize the contents of the file
|
||||
try { |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.write("Header Description:"); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.write(VERSION_TAG); |
||||
currentFileWriter.write(FILE_VERSION); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.write( |
||||
"Raw,ElapsedRealtimeMillis,TimeNanos,LeapSecond,TimeUncertaintyNanos,FullBiasNanos," |
||||
+ "BiasNanos,BiasUncertaintyNanos,DriftNanosPerSecond,DriftUncertaintyNanosPerSecond," |
||||
+ "HardwareClockDiscontinuityCount, Svid,TimeOffsetNanos,State,ReceivedSvTimeNanos," |
||||
+ "ReceivedSvTimeUncertaintyNanos,Cn0DbHz,PseudorangeRateMetersPerSecond," |
||||
+ "PseudorangeRateUncertaintyMetersPerSecond," |
||||
+ "AccumulatedDeltaRangeState,AccumulatedDeltaRangeMeters," |
||||
+ "AccumulatedDeltaRangeUncertaintyMeters,CarrierFrequencyHz,CarrierCycles," |
||||
+ "CarrierPhase,CarrierPhaseUncertainty,MultipathIndicator,SnrInDb," |
||||
+ "ConstellationType"); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.write( |
||||
"Fix,Provider,Latitude,Longitude,Altitude,Speed,Accuracy,(UTC)TimeInMs"); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.write("Nav,Svid,Type,Status,MessageId,Sub-messageId,Data(Bytes)"); |
||||
currentFileWriter.newLine(); |
||||
currentFileWriter.write(COMMENT_START); |
||||
currentFileWriter.newLine(); |
||||
} catch (IOException e) { |
||||
logException("Count not initialize file: " + currentFilePath, e); |
||||
return; |
||||
} |
||||
|
||||
if (mFileWriter != null) { |
||||
try { |
||||
mFileWriter.close(); |
||||
} catch (IOException e) { |
||||
logException("Unable to close all file streams.", e); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
mFile = currentFile; |
||||
mFileWriter = currentFileWriter; |
||||
Toast.makeText(mContext, "File opened: " + currentFilePath, Toast.LENGTH_SHORT).show(); |
||||
|
||||
// To make sure that files do not fill up the external storage:
|
||||
// - Remove all empty files
|
||||
FileFilter filter = new FileToDeleteFilter(mFile); |
||||
for (File existingFile : baseDirectory.listFiles(filter)) { |
||||
existingFile.delete(); |
||||
} |
||||
// - Trim the number of files with data
|
||||
File[] existingFiles = baseDirectory.listFiles(); |
||||
int filesToDeleteCount = existingFiles.length - MAX_FILES_STORED; |
||||
if (filesToDeleteCount > 0) { |
||||
Arrays.sort(existingFiles); |
||||
for (int i = 0; i < filesToDeleteCount; ++i) { |
||||
existingFiles[i].delete(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Send the current log via email or other options selected from a pop menu shown to the user. A |
||||
* new log is started when calling this function. |
||||
*/ |
||||
public void send() { |
||||
if (mFile == null) { |
||||
return; |
||||
} |
||||
|
||||
Intent emailIntent = new Intent(Intent.ACTION_SEND); |
||||
emailIntent.setType("*/*"); |
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "SensorLog"); |
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, ""); |
||||
// attach the file
|
||||
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(mFile)); |
||||
getUiComponent().startActivity(Intent.createChooser(emailIntent, "Send log..")); |
||||
if (mFileWriter != null) { |
||||
try { |
||||
mFileWriter.close(); |
||||
mFileWriter = null; |
||||
} catch (IOException e) { |
||||
logException("Unable to close all file streams.", e); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onProviderEnabled(String provider) {} |
||||
|
||||
@Override |
||||
public void onProviderDisabled(String provider) {} |
||||
|
||||
@Override |
||||
public void onLocationChanged(Location location) { |
||||
if (location.getProvider().equals(LocationManager.GPS_PROVIDER)) { |
||||
synchronized (mFileLock) { |
||||
if (mFileWriter == null) { |
||||
return; |
||||
} |
||||
String locationStream = |
||||
String.format( |
||||
Locale.US, |
||||
"Fix,%s,%f,%f,%f,%f,%f,%d", |
||||
location.getProvider(), |
||||
location.getLatitude(), |
||||
location.getLongitude(), |
||||
location.getAltitude(), |
||||
location.getSpeed(), |
||||
location.getAccuracy(), |
||||
location.getTime()); |
||||
try { |
||||
mFileWriter.write(locationStream); |
||||
mFileWriter.newLine(); |
||||
} catch (IOException e) { |
||||
logException(ERROR_WRITING_FILE, e); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onLocationStatusChanged(String provider, int status, Bundle extras) {} |
||||
|
||||
@Override |
||||
public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) { |
||||
synchronized (mFileLock) { |
||||
if (mFileWriter == null) { |
||||
return; |
||||
} |
||||
GnssClock gnssClock = event.getClock(); |
||||
for (GnssMeasurement measurement : event.getMeasurements()) { |
||||
try { |
||||
writeGnssMeasurementToFile(gnssClock, measurement); |
||||
} catch (IOException e) { |
||||
logException(ERROR_WRITING_FILE, e); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onGnssMeasurementsStatusChanged(int status) {} |
||||
|
||||
@Override |
||||
public void onGnssNavigationMessageReceived(GnssNavigationMessage navigationMessage) { |
||||
synchronized (mFileLock) { |
||||
if (mFileWriter == null) { |
||||
return; |
||||
} |
||||
StringBuilder builder = new StringBuilder("Nav"); |
||||
builder.append(RECORD_DELIMITER); |
||||
builder.append(navigationMessage.getSvid()); |
||||
builder.append(RECORD_DELIMITER); |
||||
builder.append(navigationMessage.getType()); |
||||
builder.append(RECORD_DELIMITER); |
||||
|
||||
int status = navigationMessage.getStatus(); |
||||
builder.append(status); |
||||
builder.append(RECORD_DELIMITER); |
||||
builder.append(navigationMessage.getMessageId()); |
||||
builder.append(RECORD_DELIMITER); |
||||
builder.append(navigationMessage.getSubmessageId()); |
||||
byte[] data = navigationMessage.getData(); |
||||
for (byte word : data) { |
||||
builder.append(RECORD_DELIMITER); |
||||
builder.append(word); |
||||
} |
||||
try { |
||||
mFileWriter.write(builder.toString()); |
||||
mFileWriter.newLine(); |
||||
} catch (IOException e) { |
||||
logException(ERROR_WRITING_FILE, e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onGnssNavigationMessageStatusChanged(int status) {} |
||||
|
||||
@Override |
||||
public void onGnssStatusChanged(GnssStatus gnssStatus) {} |
||||
|
||||
@Override |
||||
public void onNmeaReceived(long timestamp, String s) {} |
||||
|
||||
@Override |
||||
public void onListenerRegistration(String listener, boolean result) {} |
||||
|
||||
private void writeGnssMeasurementToFile(GnssClock clock, GnssMeasurement measurement) |
||||
throws IOException { |
||||
String clockStream = |
||||
String.format( |
||||
"Raw,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", |
||||
SystemClock.elapsedRealtime(), |
||||
clock.getTimeNanos(), |
||||
clock.hasLeapSecond() ? clock.getLeapSecond() : "", |
||||
clock.hasTimeUncertaintyNanos() ? clock.getTimeUncertaintyNanos() : "", |
||||
clock.getFullBiasNanos(), |
||||
clock.hasBiasNanos() ? clock.getBiasNanos() : "", |
||||
clock.hasBiasUncertaintyNanos() ? clock.getBiasUncertaintyNanos() : "", |
||||
clock.hasDriftNanosPerSecond() ? clock.getDriftNanosPerSecond() : "", |
||||
clock.hasDriftUncertaintyNanosPerSecond() |
||||
? clock.getDriftUncertaintyNanosPerSecond() |
||||
: "", |
||||
clock.getHardwareClockDiscontinuityCount() + ","); |
||||
mFileWriter.write(clockStream); |
||||
|
||||
String measurementStream = |
||||
String.format( |
||||
"%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", |
||||
measurement.getSvid(), |
||||
measurement.getTimeOffsetNanos(), |
||||
measurement.getState(), |
||||
measurement.getReceivedSvTimeNanos(), |
||||
measurement.getReceivedSvTimeUncertaintyNanos(), |
||||
measurement.getCn0DbHz(), |
||||
measurement.getPseudorangeRateMetersPerSecond(), |
||||
measurement.getPseudorangeRateUncertaintyMetersPerSecond(), |
||||
measurement.getAccumulatedDeltaRangeState(), |
||||
measurement.getAccumulatedDeltaRangeMeters(), |
||||
measurement.getAccumulatedDeltaRangeUncertaintyMeters(), |
||||
measurement.hasCarrierFrequencyHz() ? measurement.getCarrierFrequencyHz() : "", |
||||
measurement.hasCarrierCycles() ? measurement.getCarrierCycles() : "", |
||||
measurement.hasCarrierPhase() ? measurement.getCarrierPhase() : "", |
||||
measurement.hasCarrierPhaseUncertainty() |
||||
? measurement.getCarrierPhaseUncertainty() |
||||
: "", |
||||
measurement.getMultipathIndicator(), |
||||
measurement.hasSnrInDb() ? measurement.getSnrInDb() : "", |
||||
measurement.getConstellationType()); |
||||
mFileWriter.write(measurementStream); |
||||
mFileWriter.newLine(); |
||||
} |
||||
|
||||
private void logException(String errorMessage, Exception e) { |
||||
Log.e(GnssContainer.TAG + TAG, errorMessage, e); |
||||
Toast.makeText(mContext, errorMessage, Toast.LENGTH_LONG).show(); |
||||
} |
||||
|
||||
private void logError(String errorMessage) { |
||||
Log.e(GnssContainer.TAG + TAG, errorMessage); |
||||
Toast.makeText(mContext, errorMessage, Toast.LENGTH_LONG).show(); |
||||
} |
||||
|
||||
/** |
||||
* Implements a {@link FileFilter} to delete files that are not in the |
||||
* {@link FileToDeleteFilter#mRetainedFiles}. |
||||
*/ |
||||
private static class FileToDeleteFilter implements FileFilter { |
||||
private final List<File> mRetainedFiles; |
||||
|
||||
public FileToDeleteFilter(File... retainedFiles) { |
||||
this.mRetainedFiles = Arrays.asList(retainedFiles); |
||||
} |
||||
|
||||
/** |
||||
* Returns {@code true} to delete the file, and {@code false} to keep the file. |
||||
* |
||||
* <p>Files are deleted if they are not in the {@link FileToDeleteFilter#mRetainedFiles} list. |
||||
*/ |
||||
@Override |
||||
public boolean accept(File pathname) { |
||||
if (pathname == null || !pathname.exists()) { |
||||
return false; |
||||
} |
||||
if (mRetainedFiles.contains(pathname)) { |
||||
return false; |
||||
} |
||||
return pathname.length() < MINIMUM_USABLE_FILE_SIZE_BYTES; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,289 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import android.content.Context; |
||||
import android.location.GnssMeasurementsEvent; |
||||
import android.location.GnssNavigationMessage; |
||||
import android.location.GnssStatus; |
||||
import android.location.Location; |
||||
import android.location.LocationListener; |
||||
import android.location.LocationManager; |
||||
import android.location.OnNmeaMessageListener; |
||||
import android.os.Bundle; |
||||
import android.os.SystemClock; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* A container for GPS related API calls, it binds the {@link LocationManager} with {@link UiLogger} |
||||
*/ |
||||
public class GnssContainer { |
||||
|
||||
public static final String TAG = "GnssLogger"; |
||||
|
||||
private static final long LOCATION_RATE_GPS_MS = TimeUnit.SECONDS.toMillis(1L); |
||||
private static final long LOCATION_RATE_NETWORK_MS = TimeUnit.SECONDS.toMillis(60L); |
||||
|
||||
private boolean mLogLocations = true; |
||||
private boolean mLogNavigationMessages = true; |
||||
private boolean mLogMeasurements = true; |
||||
private boolean mLogStatuses = true; |
||||
private boolean mLogNmeas = true; |
||||
|
||||
private final List<GnssListener> mLoggers; |
||||
|
||||
private final LocationManager mLocationManager; |
||||
private final LocationListener mLocationListener = |
||||
new LocationListener() { |
||||
|
||||
@Override |
||||
public void onProviderEnabled(String provider) { |
||||
if (mLogLocations) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onProviderEnabled(provider); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onProviderDisabled(String provider) { |
||||
if (mLogLocations) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onProviderDisabled(provider); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onLocationChanged(Location location) { |
||||
if (mLogLocations) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onLocationChanged(location); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onStatusChanged(String provider, int status, Bundle extras) { |
||||
if (mLogLocations) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onLocationStatusChanged(provider, status, extras); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
private final GnssMeasurementsEvent.Callback gnssMeasurementsEventListener = |
||||
new GnssMeasurementsEvent.Callback() { |
||||
@Override |
||||
public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) { |
||||
if (mLogMeasurements) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onGnssMeasurementsReceived(event); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onStatusChanged(int status) { |
||||
if (mLogMeasurements) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onGnssMeasurementsStatusChanged(status); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
private final GnssNavigationMessage.Callback gnssNavigationMessageListener = |
||||
new GnssNavigationMessage.Callback() { |
||||
@Override |
||||
public void onGnssNavigationMessageReceived(GnssNavigationMessage event) { |
||||
if (mLogNavigationMessages) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onGnssNavigationMessageReceived(event); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onStatusChanged(int status) { |
||||
if (mLogNavigationMessages) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onGnssNavigationMessageStatusChanged(status); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
private final GnssStatus.Callback gnssStatusListener = |
||||
new GnssStatus.Callback() { |
||||
@Override |
||||
public void onStarted() {} |
||||
|
||||
@Override |
||||
public void onStopped() {} |
||||
|
||||
@Override |
||||
public void onSatelliteStatusChanged(GnssStatus status) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onGnssStatusChanged(status); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
private final OnNmeaMessageListener nmeaListener = |
||||
new OnNmeaMessageListener() { |
||||
@Override |
||||
public void onNmeaMessage(String s, long l) { |
||||
if (mLogNmeas) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onNmeaReceived(l, s); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
public GnssContainer(Context context, GnssListener... loggers) { |
||||
this.mLoggers = Arrays.asList(loggers); |
||||
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); |
||||
} |
||||
|
||||
public LocationManager getLocationManager() { |
||||
return mLocationManager; |
||||
} |
||||
|
||||
public void setLogLocations(boolean value) { |
||||
mLogLocations = value; |
||||
} |
||||
|
||||
public boolean canLogLocations() { |
||||
return mLogLocations; |
||||
} |
||||
|
||||
public void setLogNavigationMessages(boolean value) { |
||||
mLogNavigationMessages = value; |
||||
} |
||||
|
||||
public boolean canLogNavigationMessages() { |
||||
return mLogNavigationMessages; |
||||
} |
||||
|
||||
public void setLogMeasurements(boolean value) { |
||||
mLogMeasurements = value; |
||||
} |
||||
|
||||
public boolean canLogMeasurements() { |
||||
return mLogMeasurements; |
||||
} |
||||
|
||||
public void setLogStatuses(boolean value) { |
||||
mLogStatuses = value; |
||||
} |
||||
|
||||
public boolean canLogStatuses() { |
||||
return mLogStatuses; |
||||
} |
||||
|
||||
public void setLogNmeas(boolean value) { |
||||
mLogNmeas = value; |
||||
} |
||||
|
||||
public boolean canLogNmeas() { |
||||
return mLogNmeas; |
||||
} |
||||
|
||||
public void registerLocation() { |
||||
boolean isGpsProviderEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); |
||||
if (isGpsProviderEnabled) { |
||||
mLocationManager.requestLocationUpdates( |
||||
LocationManager.NETWORK_PROVIDER, |
||||
LOCATION_RATE_NETWORK_MS, |
||||
0.0f /* minDistance */, |
||||
mLocationListener); |
||||
mLocationManager.requestLocationUpdates( |
||||
LocationManager.GPS_PROVIDER, |
||||
LOCATION_RATE_GPS_MS, |
||||
0.0f /* minDistance */, |
||||
mLocationListener); |
||||
} |
||||
logRegistration("LocationUpdates", isGpsProviderEnabled); |
||||
} |
||||
|
||||
public void unregisterLocation() { |
||||
mLocationManager.removeUpdates(mLocationListener); |
||||
} |
||||
|
||||
public void registerMeasurements() { |
||||
logRegistration( |
||||
"GnssMeasurements", |
||||
mLocationManager.registerGnssMeasurementsCallback(gnssMeasurementsEventListener)); |
||||
} |
||||
|
||||
public void unregisterMeasurements() { |
||||
mLocationManager.unregisterGnssMeasurementsCallback(gnssMeasurementsEventListener); |
||||
} |
||||
|
||||
public void registerNavigation() { |
||||
logRegistration( |
||||
"GpsNavigationMessage", |
||||
mLocationManager.registerGnssNavigationMessageCallback(gnssNavigationMessageListener)); |
||||
} |
||||
|
||||
public void unregisterNavigation() { |
||||
mLocationManager.unregisterGnssNavigationMessageCallback(gnssNavigationMessageListener); |
||||
} |
||||
|
||||
public void registerGnssStatus() { |
||||
logRegistration("GnssStatus", mLocationManager.registerGnssStatusCallback(gnssStatusListener)); |
||||
} |
||||
|
||||
public void unregisterGpsStatus() { |
||||
mLocationManager.unregisterGnssStatusCallback(gnssStatusListener); |
||||
} |
||||
|
||||
public void registerNmea() { |
||||
logRegistration("Nmea", mLocationManager.addNmeaListener(nmeaListener)); |
||||
} |
||||
|
||||
public void unregisterNmea() { |
||||
mLocationManager.removeNmeaListener(nmeaListener); |
||||
} |
||||
|
||||
public void registerAll() { |
||||
registerLocation(); |
||||
registerMeasurements(); |
||||
registerNavigation(); |
||||
registerGnssStatus(); |
||||
registerNmea(); |
||||
} |
||||
|
||||
public void unregisterAll() { |
||||
unregisterLocation(); |
||||
unregisterMeasurements(); |
||||
unregisterNavigation(); |
||||
unregisterGpsStatus(); |
||||
unregisterNmea(); |
||||
} |
||||
|
||||
private void logRegistration(String listener, boolean result) { |
||||
for (GnssListener logger : mLoggers) { |
||||
logger.onListenerRegistration(listener, result); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import android.location.GnssMeasurementsEvent; |
||||
import android.location.GnssNavigationMessage; |
||||
import android.location.GnssStatus; |
||||
import android.location.Location; |
||||
import android.location.LocationListener; |
||||
import android.location.OnNmeaMessageListener; |
||||
import android.os.Bundle; |
||||
|
||||
/** A class representing an interface for logging GPS information. */ |
||||
public interface GnssListener { |
||||
|
||||
/** @see LocationListener#onProviderEnabled(String) */ |
||||
void onProviderEnabled(String provider); |
||||
/** @see LocationListener#onProviderDisabled(String) */ |
||||
void onProviderDisabled(String provider); |
||||
/** @see LocationListener#onLocationChanged(Location) */ |
||||
void onLocationChanged(Location location); |
||||
/** @see LocationListener#onStatusChanged(String, int, Bundle) */ |
||||
void onLocationStatusChanged(String provider, int status, Bundle extras); |
||||
/** |
||||
* @see android.location.GnssMeasurementsEvent.Callback# |
||||
* onGnssMeasurementsReceived(GnssMeasurementsEvent) |
||||
*/ |
||||
void onGnssMeasurementsReceived(GnssMeasurementsEvent event); |
||||
/** @see GnssMeasurementsEvent.Callback#onStatusChanged(int) */ |
||||
void onGnssMeasurementsStatusChanged(int status); |
||||
/** |
||||
* @see GnssNavigationMessage.Callback# |
||||
* onGnssNavigationMessageReceived(GnssNavigationMessage) |
||||
*/ |
||||
void onGnssNavigationMessageReceived(GnssNavigationMessage event); |
||||
/** @see GnssNavigationMessage.Callback#onStatusChanged(int) */ |
||||
void onGnssNavigationMessageStatusChanged(int status); |
||||
/** @see GnssStatus.Callback#onSatelliteStatusChanged(GnssStatus) */ |
||||
void onGnssStatusChanged(GnssStatus gnssStatus); |
||||
/** Called when the listener is registered to listen to GNSS events */ |
||||
void onListenerRegistration(String listener, boolean result); |
||||
/** @see OnNmeaMessageListener#onNmeaMessage(String, long) */ |
||||
void onNmeaReceived(long l, String s); |
||||
} |
@ -0,0 +1,83 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.InputStreamReader; |
||||
import android.app.Dialog; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.net.MailTo; |
||||
import android.net.Uri; |
||||
import android.os.Bundle; |
||||
import android.webkit.WebView; |
||||
import android.webkit.WebViewClient; |
||||
|
||||
public class HelpDialog extends Dialog { |
||||
|
||||
private static Context mContext = null; |
||||
|
||||
public HelpDialog(Context context) { |
||||
super(context); |
||||
mContext = context; |
||||
} |
||||
|
||||
@Override |
||||
public void onCreate(Bundle savedInstanceState) { |
||||
setContentView(R.layout.help); |
||||
WebView help = (WebView)findViewById(R.id.helpView); |
||||
help.setWebViewClient(new WebViewClient(){ |
||||
@Override |
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) { |
||||
if(url.startsWith("mailto:")){ |
||||
MailTo mt = MailTo.parse(url); |
||||
Intent emailIntent = new Intent(Intent.ACTION_SEND); |
||||
emailIntent.setType("*/*"); |
||||
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "GNSSLogger Feedback"); |
||||
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { mt.getTo()}); |
||||
emailIntent.putExtra(Intent.EXTRA_TEXT, ""); |
||||
mContext.startActivity(Intent.createChooser(emailIntent, "Send Feedback...")); |
||||
return true; |
||||
} |
||||
else{ |
||||
view.loadUrl(url); |
||||
} |
||||
return true; |
||||
} |
||||
}); |
||||
|
||||
String helpText = readRawTextFile(R.raw.help_contents); |
||||
help.loadData(helpText, "text/html; charset=utf-8", "utf-8"); |
||||
} |
||||
|
||||
private String readRawTextFile(int id) { |
||||
InputStream inputStream = mContext.getResources().openRawResource(id); |
||||
InputStreamReader in = new InputStreamReader(inputStream); |
||||
BufferedReader buf = new BufferedReader(in); |
||||
String line; |
||||
StringBuilder text = new StringBuilder(); |
||||
try { |
||||
while (( line = buf.readLine()) != null) |
||||
text.append(line); |
||||
} catch (IOException e) { |
||||
return null; |
||||
} |
||||
return text.toString(); |
||||
} |
||||
} |
@ -0,0 +1,163 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import android.app.Activity; |
||||
import android.app.Fragment; |
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
import android.text.Editable; |
||||
import android.text.SpannableStringBuilder; |
||||
import android.text.style.ForegroundColorSpan; |
||||
import android.view.LayoutInflater; |
||||
import android.view.View; |
||||
import android.view.View.OnClickListener; |
||||
import android.view.ViewGroup; |
||||
import android.widget.Button; |
||||
import android.widget.ScrollView; |
||||
import android.widget.TextView; |
||||
import android.widget.Toast; |
||||
|
||||
/** The UI fragment that hosts a logging view. */ |
||||
public class LoggerFragment extends Fragment { |
||||
|
||||
private TextView mLogView; |
||||
private ScrollView mScrollView; |
||||
private FileLogger mFileLogger; |
||||
private UiLogger mUiLogger; |
||||
|
||||
private final UIFragmentComponent mUiComponent = new UIFragmentComponent(); |
||||
|
||||
public void setUILogger(UiLogger value) { |
||||
mUiLogger = value; |
||||
} |
||||
|
||||
public void setFileLogger(FileLogger value) { |
||||
mFileLogger = value; |
||||
} |
||||
|
||||
@Override |
||||
public View onCreateView( |
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
||||
View newView = inflater.inflate(R.layout.fragment_log, container, false /* attachToRoot */); |
||||
mLogView = (TextView) newView.findViewById(R.id.log_view); |
||||
mScrollView = (ScrollView) newView.findViewById(R.id.log_scroll); |
||||
|
||||
UiLogger currentUiLogger = mUiLogger; |
||||
if (currentUiLogger != null) { |
||||
currentUiLogger.setUiFragmentComponent(mUiComponent); |
||||
} |
||||
FileLogger currentFileLogger = mFileLogger; |
||||
if (currentFileLogger != null) { |
||||
currentFileLogger.setUiComponent(mUiComponent); |
||||
} |
||||
|
||||
Button start = (Button) newView.findViewById(R.id.start_log); |
||||
start.setOnClickListener( |
||||
new OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
mScrollView.fullScroll(View.FOCUS_UP); |
||||
} |
||||
}); |
||||
|
||||
Button end = (Button) newView.findViewById(R.id.end_log); |
||||
end.setOnClickListener( |
||||
new OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
mScrollView.fullScroll(View.FOCUS_DOWN); |
||||
} |
||||
}); |
||||
|
||||
Button clear = (Button) newView.findViewById(R.id.clear_log); |
||||
clear.setOnClickListener( |
||||
new OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
mLogView.setText(""); |
||||
} |
||||
}); |
||||
|
||||
final Button startLog = (Button) newView.findViewById(R.id.start_logs); |
||||
final Button sendFile = (Button) newView.findViewById(R.id.send_file); |
||||
|
||||
startLog.setOnClickListener( |
||||
new OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
startLog.setEnabled(false); |
||||
sendFile.setEnabled(true); |
||||
Toast.makeText(getContext(), "Starting log...", Toast.LENGTH_LONG).show(); |
||||
mFileLogger.startNewLog(); |
||||
} |
||||
}); |
||||
|
||||
sendFile.setOnClickListener( |
||||
new OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
startLog.setEnabled(true); |
||||
sendFile.setEnabled(false); |
||||
Toast.makeText(getContext(), "Sending file...", Toast.LENGTH_LONG).show(); |
||||
mFileLogger.send(); |
||||
} |
||||
}); |
||||
|
||||
return newView; |
||||
} |
||||
|
||||
/** |
||||
* A facade for UI and Activity related operations that are required for {@link GnssListener}s. |
||||
*/ |
||||
public class UIFragmentComponent { |
||||
|
||||
private static final int MAX_LENGTH = 12000; |
||||
private static final int LOWER_THRESHOLD = (int) (MAX_LENGTH * 0.5); |
||||
|
||||
public synchronized void logTextFragment(final String tag, final String text, int color) { |
||||
final SpannableStringBuilder builder = new SpannableStringBuilder(); |
||||
builder.append(tag).append(" | ").append(text).append("\n"); |
||||
builder.setSpan( |
||||
new ForegroundColorSpan(color), |
||||
0 /* start */, |
||||
builder.length(), |
||||
SpannableStringBuilder.SPAN_INCLUSIVE_EXCLUSIVE); |
||||
|
||||
Activity activity = getActivity(); |
||||
if (activity == null) { |
||||
return; |
||||
} |
||||
activity.runOnUiThread( |
||||
new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
mLogView.append(builder); |
||||
Editable editable = mLogView.getEditableText(); |
||||
int length = editable.length(); |
||||
if (length > MAX_LENGTH) { |
||||
editable.delete(0, length - LOWER_THRESHOLD); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public void startActivity(Intent intent) { |
||||
getActivity().startActivity(intent); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,172 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import android.Manifest; |
||||
import android.app.Activity; |
||||
import android.app.Fragment; |
||||
import android.app.FragmentManager; |
||||
import android.content.pm.PackageManager; |
||||
import android.os.Build; |
||||
import android.os.Build.VERSION_CODES; |
||||
import android.os.Bundle; |
||||
import android.support.design.widget.TabLayout; |
||||
import android.support.design.widget.TabLayout.TabLayoutOnPageChangeListener; |
||||
import android.support.v13.app.FragmentPagerAdapter; |
||||
import android.support.v13.app.FragmentStatePagerAdapter; |
||||
import android.support.v4.app.ActivityCompat; |
||||
import android.support.v4.content.ContextCompat; |
||||
import android.support.v4.view.ViewPager; |
||||
import android.support.v7.app.AppCompatActivity; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
/** The activity for the application. */ |
||||
public class MainActivity extends AppCompatActivity { |
||||
|
||||
private static final int LOCATION_REQUEST_ID = 1; |
||||
private static final String[] REQUIRED_PERMISSIONS = { |
||||
Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE |
||||
}; |
||||
private static final int NUMBER_OF_FRAGMENTS = 2; |
||||
private static final int FRAGMENT_INDEX_SETTING = 0; |
||||
private static final int FRAGMENT_INDEX_LOGGER = 1; |
||||
|
||||
private GnssContainer mGnssContainer; |
||||
private UiLogger mUiLogger; |
||||
private FileLogger mFileLogger; |
||||
private Fragment[] mFragments; |
||||
|
||||
@Override |
||||
protected void onStart() { |
||||
super.onStart(); |
||||
} |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setContentView(R.layout.activity_main); |
||||
requestPermissionAndSetupFragments(this); |
||||
} |
||||
|
||||
/** |
||||
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to one of the |
||||
* sections/tabs/pages. |
||||
*/ |
||||
public class ViewPagerAdapter extends FragmentStatePagerAdapter { |
||||
|
||||
public ViewPagerAdapter(FragmentManager fm) { |
||||
super(fm); |
||||
} |
||||
|
||||
@Override |
||||
public Fragment getItem(int position) { |
||||
switch (position) { |
||||
case FRAGMENT_INDEX_SETTING: |
||||
return mFragments[FRAGMENT_INDEX_SETTING]; |
||||
case FRAGMENT_INDEX_LOGGER: |
||||
return mFragments[FRAGMENT_INDEX_LOGGER]; |
||||
default: |
||||
throw new IllegalArgumentException("Invalid section: " + position); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int getCount() { |
||||
// Show total pages.
|
||||
return 2; |
||||
} |
||||
|
||||
@Override |
||||
public CharSequence getPageTitle(int position) { |
||||
Locale locale = Locale.getDefault(); |
||||
switch (position) { |
||||
case 0: |
||||
return getString(R.string.title_settings).toUpperCase(locale); |
||||
case 1: |
||||
return getString(R.string.title_log).toUpperCase(locale); |
||||
default: |
||||
return super.getPageTitle(position); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onRequestPermissionsResult( |
||||
int requestCode, String permissions[], int[] grantResults) { |
||||
if (requestCode == LOCATION_REQUEST_ID) { |
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { |
||||
setupFragments(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void setupFragments() { |
||||
mUiLogger = new UiLogger(); |
||||
mFileLogger = new FileLogger(getApplicationContext()); |
||||
mGnssContainer = new GnssContainer(getApplicationContext(), mUiLogger, mFileLogger); |
||||
mFragments = new Fragment[NUMBER_OF_FRAGMENTS]; |
||||
SettingsFragment settingsFragment = new SettingsFragment(); |
||||
settingsFragment.setGpsContainer(mGnssContainer); |
||||
mFragments[FRAGMENT_INDEX_SETTING] = settingsFragment; |
||||
|
||||
LoggerFragment loggerFragment = new LoggerFragment(); |
||||
loggerFragment.setUILogger(mUiLogger); |
||||
loggerFragment.setFileLogger(mFileLogger); |
||||
mFragments[FRAGMENT_INDEX_LOGGER] = loggerFragment; |
||||
|
||||
|
||||
// The viewpager that will host the section contents.
|
||||
ViewPager viewPager = (ViewPager) findViewById(R.id.pager); |
||||
viewPager.setOffscreenPageLimit(2); |
||||
ViewPagerAdapter adapter = new ViewPagerAdapter(getFragmentManager()); |
||||
viewPager.setAdapter(adapter); |
||||
|
||||
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); |
||||
tabLayout.setTabsFromPagerAdapter(adapter); |
||||
|
||||
// Set a listener via setOnTabSelectedListener(OnTabSelectedListener) to be notified when any
|
||||
// tab's selection state has been changed.
|
||||
tabLayout.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager)); |
||||
|
||||
// Use a TabLayout.TabLayoutOnPageChangeListener to forward the scroll and selection changes to
|
||||
// this layout
|
||||
viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(tabLayout)); |
||||
} |
||||
|
||||
private boolean hasPermissions(Activity activity) { |
||||
if (Build.VERSION.SDK_INT < VERSION_CODES.M) { |
||||
// Permissions granted at install time.
|
||||
return true; |
||||
} |
||||
for (String p : REQUIRED_PERMISSIONS) { |
||||
if (ContextCompat.checkSelfPermission(activity, p) != PackageManager.PERMISSION_GRANTED) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
private void requestPermissionAndSetupFragments(final Activity activity) { |
||||
if (hasPermissions(activity)) { |
||||
setupFragments(); |
||||
} else { |
||||
ActivityCompat.requestPermissions(activity, REQUIRED_PERMISSIONS, LOCATION_REQUEST_ID); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,219 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import android.app.Fragment; |
||||
import android.location.LocationManager; |
||||
import android.os.Build; |
||||
import android.os.Bundle; |
||||
import android.util.Log; |
||||
import android.view.LayoutInflater; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.CompoundButton; |
||||
import android.widget.CompoundButton.OnCheckedChangeListener; |
||||
import android.widget.Switch; |
||||
import android.widget.TextView; |
||||
import android.widget.Toast; |
||||
import com.google.android.apps.location.gps.gnsslogger.GnssContainer; |
||||
import java.lang.reflect.InvocationTargetException; |
||||
import android.widget.Button; |
||||
|
||||
/** |
||||
* The UI fragment showing a set of configurable settings for the client to request GPS data. |
||||
*/ |
||||
public class SettingsFragment extends Fragment { |
||||
|
||||
public static final String TAG = ":SettingsFragment"; |
||||
private GnssContainer mGpsContainer; |
||||
private HelpDialog helpDialog; |
||||
|
||||
public void setGpsContainer(GnssContainer value) { |
||||
mGpsContainer = value; |
||||
} |
||||
|
||||
@Override |
||||
public View onCreateView( |
||||
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
||||
View view = inflater.inflate(R.layout.fragment_main, container, false /* attachToRoot */); |
||||
|
||||
final Switch registerLocation = (Switch) view.findViewById(R.id.register_location); |
||||
final TextView registerLocationLabel = |
||||
(TextView) view.findViewById(R.id.register_location_label); |
||||
//set the switch to OFF
|
||||
registerLocation.setChecked(false); |
||||
registerLocationLabel.setText("Switch is OFF"); |
||||
registerLocation.setOnCheckedChangeListener( |
||||
new OnCheckedChangeListener() { |
||||
|
||||
@Override |
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
||||
|
||||
if (isChecked) { |
||||
mGpsContainer.registerLocation(); |
||||
registerLocationLabel.setText("Switch is ON"); |
||||
} else { |
||||
mGpsContainer.unregisterLocation(); |
||||
registerLocationLabel.setText("Switch is OFF"); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
final Switch registerMeasurements = (Switch) view.findViewById(R.id.register_measurements); |
||||
final TextView registerMeasurementsLabel = |
||||
(TextView) view.findViewById(R.id.register_measurement_label); |
||||
//set the switch to OFF
|
||||
registerMeasurements.setChecked(false); |
||||
registerMeasurementsLabel.setText("Switch is OFF"); |
||||
registerMeasurements.setOnCheckedChangeListener( |
||||
new OnCheckedChangeListener() { |
||||
|
||||
@Override |
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
||||
|
||||
if (isChecked) { |
||||
mGpsContainer.registerMeasurements(); |
||||
registerMeasurementsLabel.setText("Switch is ON"); |
||||
} else { |
||||
mGpsContainer.unregisterMeasurements(); |
||||
registerMeasurementsLabel.setText("Switch is OFF"); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
final Switch registerNavigation = (Switch) view.findViewById(R.id.register_navigation); |
||||
final TextView registerNavigationLabel = |
||||
(TextView) view.findViewById(R.id.register_navigation_label); |
||||
//set the switch to OFF
|
||||
registerNavigation.setChecked(false); |
||||
registerNavigationLabel.setText("Switch is OFF"); |
||||
registerNavigation.setOnCheckedChangeListener( |
||||
new OnCheckedChangeListener() { |
||||
|
||||
@Override |
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
||||
|
||||
if (isChecked) { |
||||
mGpsContainer.registerNavigation(); |
||||
registerNavigationLabel.setText("Switch is ON"); |
||||
} else { |
||||
mGpsContainer.unregisterNavigation(); |
||||
registerNavigationLabel.setText("Switch is OFF"); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
final Switch registerGpsStatus = (Switch) view.findViewById(R.id.register_status); |
||||
final TextView registerGpsStatusLabel = |
||||
(TextView) view.findViewById(R.id.register_status_label); |
||||
//set the switch to OFF
|
||||
registerGpsStatus.setChecked(false); |
||||
registerGpsStatusLabel.setText("Switch is OFF"); |
||||
registerGpsStatus.setOnCheckedChangeListener( |
||||
new OnCheckedChangeListener() { |
||||
|
||||
@Override |
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
||||
|
||||
if (isChecked) { |
||||
mGpsContainer.registerGnssStatus(); |
||||
registerGpsStatusLabel.setText("Switch is ON"); |
||||
} else { |
||||
mGpsContainer.unregisterGpsStatus(); |
||||
registerGpsStatusLabel.setText("Switch is OFF"); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
final Switch registerNmea = (Switch) view.findViewById(R.id.register_nmea); |
||||
final TextView registerNmeaLabel = (TextView) view.findViewById(R.id.register_nmea_label); |
||||
//set the switch to OFF
|
||||
registerNmea.setChecked(false); |
||||
registerNmeaLabel.setText("Switch is OFF"); |
||||
registerNmea.setOnCheckedChangeListener( |
||||
new OnCheckedChangeListener() { |
||||
|
||||
@Override |
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
||||
|
||||
if (isChecked) { |
||||
mGpsContainer.registerNmea(); |
||||
registerNmeaLabel.setText("Switch is ON"); |
||||
} else { |
||||
mGpsContainer.unregisterNmea(); |
||||
registerNmeaLabel.setText("Switch is OFF"); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
Button help = (Button) view.findViewById(R.id.help); |
||||
helpDialog = new HelpDialog(getContext()); |
||||
helpDialog.setTitle("Help contents"); |
||||
helpDialog.create(); |
||||
|
||||
help.setOnClickListener(new View.OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
helpDialog.show(); |
||||
} |
||||
}); |
||||
|
||||
Button exit = (Button) view.findViewById(R.id.exit); |
||||
exit.setOnClickListener(new View.OnClickListener() { |
||||
@Override |
||||
public void onClick(View view) { |
||||
getActivity().finishAffinity(); |
||||
} |
||||
}); |
||||
|
||||
TextView swInfo = (TextView) view.findViewById(R.id.sw_info); |
||||
|
||||
java.lang.reflect.Method method; |
||||
LocationManager locationManager = mGpsContainer.getLocationManager(); |
||||
try { |
||||
method = locationManager.getClass().getMethod("getGnssYearOfHardware"); |
||||
int hwYear = (int) method.invoke(locationManager); |
||||
if (hwYear == 0) { |
||||
swInfo.append("HW Year: " + "2015 or older \n"); |
||||
} else { |
||||
swInfo.append("HW Year: " + hwYear + "\n"); |
||||
} |
||||
|
||||
} catch (NoSuchMethodException e) { |
||||
logException("No such method exception: ", e); |
||||
return null; |
||||
} catch (IllegalAccessException e) { |
||||
logException("Illegal Access exception: ", e); |
||||
return null; |
||||
} catch (InvocationTargetException e) { |
||||
logException("Invocation Target Exception: ", e); |
||||
return null; |
||||
} |
||||
|
||||
String platfromVersionString = Build.VERSION.RELEASE; |
||||
swInfo.append("Platform: " + platfromVersionString + "\n"); |
||||
int apiLivelInt = Build.VERSION.SDK_INT; |
||||
swInfo.append("Api Level: " + apiLivelInt); |
||||
|
||||
return view; |
||||
} |
||||
|
||||
private void logException(String errorMessage, Exception e) { |
||||
Log.e(GnssContainer.TAG + TAG, errorMessage, e); |
||||
Toast.makeText(getContext(), errorMessage, Toast.LENGTH_LONG).show(); |
||||
} |
||||
} |
@ -0,0 +1,220 @@
|
||||
/* |
||||
* Copyright (C) 2016 The Android Open Source Project |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.google.android.apps.location.gps.gnsslogger; |
||||
|
||||
import android.graphics.Color; |
||||
import android.location.GnssMeasurementsEvent; |
||||
import android.location.GnssNavigationMessage; |
||||
import android.location.GnssStatus; |
||||
import android.location.Location; |
||||
import android.location.LocationProvider; |
||||
import android.os.Bundle; |
||||
import android.util.Log; |
||||
import com.google.android.apps.location.gps.gnsslogger.LoggerFragment.UIFragmentComponent; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* A class representing a UI logger for the application. Its responsibility is show information in |
||||
* the UI. |
||||
*/ |
||||
public class UiLogger implements GnssListener { |
||||
|
||||
private static final long EARTH_RADIUS_METERS = 6371000; |
||||
private static final int USED_COLOR = Color.rgb(0x4a, 0x5f, 0x70); |
||||
|
||||
public UiLogger() {} |
||||
|
||||
private UIFragmentComponent mUiFragmentComponent; |
||||
|
||||
public synchronized UIFragmentComponent getUiFragmentComponent() { |
||||
return mUiFragmentComponent; |
||||
} |
||||
|
||||
public synchronized void setUiFragmentComponent(UIFragmentComponent value) { |
||||
mUiFragmentComponent = value; |
||||
} |
||||
|
||||
@Override |
||||
public void onProviderEnabled(String provider) { |
||||
logLocationEvent("onProviderEnabled: " + provider); |
||||
} |
||||
|
||||
@Override |
||||
public void onProviderDisabled(String provider) { |
||||
logLocationEvent("onProviderDisabled: " + provider); |
||||
} |
||||
|
||||
@Override |
||||
public void onLocationChanged(Location location) { |
||||
logLocationEvent("onLocationChanged: " + location); |
||||
} |
||||
|
||||
@Override |
||||
public void onLocationStatusChanged(String provider, int status, Bundle extras) { |
||||
String message = |
||||
String.format( |
||||
"onStatusChanged: provider=%s, status=%s, extras=%s", |
||||
provider, locationStatusToString(status), extras); |
||||
logLocationEvent(message); |
||||
} |
||||
|
||||
@Override |
||||
public void onGnssMeasurementsReceived(GnssMeasurementsEvent event) { |
||||
logMeasurementEvent("onGnsssMeasurementsReceived: " + event); |
||||
} |
||||
|
||||
@Override |
||||
public void onGnssMeasurementsStatusChanged(int status) { |
||||
logMeasurementEvent("onStatusChanged: " + gnssMeasurementsStatusToString(status)); |
||||
} |
||||
|
||||
@Override |
||||
public void onGnssNavigationMessageReceived(GnssNavigationMessage event) { |
||||
logNavigationMessageEvent("onGnssNavigationMessageReceived: " + event); |
||||
} |
||||
|
||||
@Override |
||||
public void onGnssNavigationMessageStatusChanged(int status) { |
||||
logNavigationMessageEvent("onStatusChanged: " + getGnssNavigationMessageStatus(status)); |
||||
} |
||||
|
||||
@Override |
||||
public void onGnssStatusChanged(GnssStatus gnssStatus) { |
||||
logStatusEvent("onGnssStatusChanged: " + gnssStatusToString(gnssStatus)); |
||||
} |
||||
|
||||
@Override |
||||
public void onNmeaReceived(long timestamp, String s) { |
||||
logNmeaEvent(String.format("onNmeaReceived: timestamp=%d, %s", timestamp, s)); |
||||
} |
||||
|
||||
@Override |
||||
public void onListenerRegistration(String listener, boolean result) { |
||||
logEvent("Registration", String.format("add%sListener: %b", listener, result), USED_COLOR); |
||||
} |
||||
|
||||
private void logMeasurementEvent(String event) { |
||||
logEvent("Measurement", event, USED_COLOR); |
||||
} |
||||
|
||||
private void logNavigationMessageEvent(String event) { |
||||
logEvent("NavigationMsg", event, USED_COLOR); |
||||
} |
||||
|
||||
private void logStatusEvent(String event) { |
||||
logEvent("Status", event, USED_COLOR); |
||||
} |
||||
|
||||
private void logNmeaEvent(String event) { |
||||
logEvent("Nmea", event, USED_COLOR); |
||||
} |
||||
|
||||
private void logEvent(String tag, String message, int color) { |
||||
String composedTag = GnssContainer.TAG + tag; |
||||
Log.d(composedTag, message); |
||||
logText(tag, message, color); |
||||
} |
||||
|
||||
private void logText(String tag, String text, int color) { |
||||
UIFragmentComponent component = getUiFragmentComponent(); |
||||
if (component != null) { |
||||
component.logTextFragment(tag, text, color); |
||||
} |
||||
} |
||||
|
||||
private String locationStatusToString(int status) { |
||||
switch (status) { |
||||
case LocationProvider.AVAILABLE: |
||||
return "AVAILABLE"; |
||||
case LocationProvider.OUT_OF_SERVICE: |
||||
return "OUT_OF_SERVICE"; |
||||
case LocationProvider.TEMPORARILY_UNAVAILABLE: |
||||
return "TEMPORARILY_UNAVAILABLE"; |
||||
default: |
||||
return "<Unknown>"; |
||||
} |
||||
} |
||||
|
||||
private String gnssMeasurementsStatusToString(int status) { |
||||
switch (status) { |
||||
case GnssMeasurementsEvent.Callback.STATUS_NOT_SUPPORTED: |
||||
return "NOT_SUPPORTED"; |
||||
case GnssMeasurementsEvent.Callback.STATUS_READY: |
||||
return "READY"; |
||||
case GnssMeasurementsEvent.Callback.STATUS_LOCATION_DISABLED: |
||||
return "GNSS_LOCATION_DISABLED"; |
||||
default: |
||||
return "<Unknown>"; |
||||
} |
||||
} |
||||
|
||||
private String getGnssNavigationMessageStatus(int status) { |
||||
switch (status) { |
||||
case GnssNavigationMessage.STATUS_UNKNOWN: |
||||
return "Status Unknown"; |
||||
case GnssNavigationMessage.STATUS_PARITY_PASSED: |
||||
return "READY"; |
||||
case GnssNavigationMessage.STATUS_PARITY_REBUILT: |
||||
return "Status Parity Rebuilt"; |
||||
default: |
||||
return "<Unknown>"; |
||||
} |
||||
} |
||||
|
||||
private String gnssStatusToString(GnssStatus gnssStatus) { |
||||
|
||||
StringBuilder builder = new StringBuilder("SATELLITE_STATUS | [Satellites:\n"); |
||||
for (int i = 0; i < gnssStatus.getSatelliteCount(); i++) { |
||||
builder |
||||
.append("Constellation = ") |
||||
.append(getConstellationName(gnssStatus.getConstellationType(i))) |
||||
.append(", "); |
||||
builder.append("Svid = ").append(gnssStatus.getSvid(i)).append(", "); |
||||
builder.append("Cn0DbHz = ").append(gnssStatus.getCn0DbHz(i)).append(", "); |
||||
builder.append("Elevation = ").append(gnssStatus.getElevationDegrees(i)).append(", "); |
||||
builder.append("Azimuth = ").append(gnssStatus.getAzimuthDegrees(i)).append(", "); |
||||
builder.append("hasEphemeris = ").append(gnssStatus.hasEphemerisData(i)).append(", "); |
||||
builder.append("hasAlmanac = ").append(gnssStatus.hasAlmanacData(i)).append(", "); |
||||
builder.append("usedInFix = ").append(gnssStatus.usedInFix(i)).append("\n"); |
||||
} |
||||
builder.append("]"); |
||||
return builder.toString(); |
||||
} |
||||
|
||||
private void logLocationEvent(String event) { |
||||
logEvent("Location", event, USED_COLOR); |
||||
} |
||||
|
||||
private String getConstellationName(int id) { |
||||
switch (id) { |
||||
case 1: |
||||
return "GPS"; |
||||
case 2: |
||||
return "SBAS"; |
||||
case 3: |
||||
return "GLONASS"; |
||||
case 4: |
||||
return "QZSS"; |
||||
case 5: |
||||
return "BEIDOU"; |
||||
case 6: |
||||
return "GALILEO"; |
||||
default: |
||||
return "UNKNOWN"; |
||||
} |
||||
} |
||||
} |
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical"> |
||||
|
||||
<android.support.design.widget.TabLayout |
||||
android:id="@+id/tab_layout" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" /> |
||||
|
||||
<android.support.v4.view.ViewPager |
||||
android:id="@+id/pager" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="fill_parent" |
||||
android:layout_below="@id/tab_layout"/> |
||||
|
||||
</LinearLayout> |
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical" > |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<Button |
||||
android:id="@+id/start_log" |
||||
android:text="\u2770 Start" |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" /> |
||||
<Button |
||||
android:id="@+id/clear_log" |
||||
android:text="Clear" |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" /> |
||||
<Button |
||||
android:id="@+id/end_log" |
||||
android:text="End \u2771" |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<ScrollView |
||||
android:id="@+id/log_scroll" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="0dp" |
||||
android:layout_weight="1"> |
||||
|
||||
<TextView |
||||
android:id="@+id/log_view" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" /> |
||||
|
||||
</ScrollView> |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<Button |
||||
android:id="@+id/start_logs" |
||||
android:text="Start Log" |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content"/> |
||||
|
||||
<Button |
||||
android:id="@+id/send_file" |
||||
android:text="Stop & Send" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_weight="1"/> |
||||
|
||||
</LinearLayout> |
||||
|
||||
</LinearLayout> |
@ -0,0 +1,155 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical" |
||||
android:paddingLeft="@dimen/activity_horizontal_margin" |
||||
android:paddingRight="@dimen/activity_horizontal_margin" |
||||
android:paddingTop="@dimen/activity_vertical_margin" |
||||
android:paddingBottom="@dimen/activity_vertical_margin" |
||||
tools:context=".MainActivity"> |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:textStyle="bold" |
||||
android:layout_marginTop="15dp" |
||||
android:id="@+id/register_location_label" /> |
||||
<Switch |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:id="@+id/register_location" |
||||
android:singleLine="true" |
||||
android:layout_marginTop="15dp" |
||||
android:text="@string/location_label" /> |
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:textStyle="bold" |
||||
android:layout_marginTop="15dp" |
||||
android:id="@+id/register_measurement_label" /> |
||||
<Switch |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:id="@+id/register_measurements" |
||||
android:singleLine="true" |
||||
android:layout_marginTop="15dp" |
||||
android:text="@string/measurements_label" /> |
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="center_vertical" |
||||
android:textStyle="bold" |
||||
android:layout_marginTop="15dp" |
||||
android:id="@+id/register_navigation_label" /> |
||||
<Switch |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:id="@+id/register_navigation" |
||||
android:singleLine="true" |
||||
android:layout_marginTop="15dp" |
||||
android:text="@string/nav_msg_label" /> |
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:textStyle="bold" |
||||
android:layout_marginTop="15dp" |
||||
android:id="@+id/register_status_label" /> |
||||
<Switch |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:id="@+id/register_status" |
||||
android:singleLine="true" |
||||
android:layout_marginTop="15dp" |
||||
android:text="@string/gnss_status_label" /> |
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:textStyle="bold" |
||||
android:layout_marginTop="15dp" |
||||
android:id="@+id/register_nmea_label" /> |
||||
<Switch |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:id="@+id/register_nmea" |
||||
android:singleLine="true" |
||||
android:layout_marginTop="15dp" |
||||
android:text="@string/nmea_label" /> |
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:orientation="horizontal" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
<Button |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/help" |
||||
android:layout_marginTop="150dp" |
||||
android:id="@+id/help" |
||||
android:singleLine="true" /> |
||||
<Button |
||||
android:layout_width="0dp" |
||||
android:layout_weight="1" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/exit" |
||||
android:layout_marginTop="150dp" |
||||
android:id="@+id/exit" |
||||
android:singleLine="true" /> |
||||
</LinearLayout> |
||||
|
||||
<TextView |
||||
android:id="@+id/sw_info" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="0dp" |
||||
android:layout_weight="1" |
||||
android:textStyle="bold" |
||||
android:gravity="bottom"/> |
||||
|
||||
<TextView |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:gravity="end|bottom" |
||||
android:textStyle="italic|bold" |
||||
android:text="@string/app_version"/> |
||||
|
||||
</LinearLayout> |
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="fill_parent" |
||||
android:layout_height="fill_parent" |
||||
android:orientation="vertical" > |
||||
|
||||
<android.webkit.WebView |
||||
android:id="@+id/helpView" |
||||
android:layout_width="fill_parent" |
||||
android:layout_height="wrap_content" > |
||||
</android.webkit.WebView> |
||||
|
||||
</LinearLayout> |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,20 @@
|
||||
<a href="#about_apphelp">About AppHelp</a> |
||||
<br> |
||||
<a href="#feedback">Feedback</a> |
||||
<br> |
||||
<a name="about_apphelp" id="about_apphelp"> |
||||
<h3>About AppHelp</h3> |
||||
<ul> |
||||
<li>Start Log button: Starts logging when pushed.</li> |
||||
<li>Stop & Send button: Stops logging and shows dialog to send the file via email or other options.</li> |
||||
</ul> |
||||
|
||||
</a> |
||||
<br> |
||||
<a name="feedback" id="feedback"> |
||||
<h3>Feedback</h3> |
||||
Any comments, feedback, suggestions on GNSSLogger please write to us using the link below. |
||||
<br> |
||||
<a href="mailto:pseudoranges-feedback@google.com">Contact support</a> |
||||
</a> |
||||
<br> |
@ -0,0 +1,6 @@
|
||||
<resources> |
||||
<!-- Example customization of dimensions originally defined in res/values/dimens.xml |
||||
(such as screen margins) for screens with more than 820dp of available width. This |
||||
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> |
||||
<dimen name="activity_horizontal_margin">64dp</dimen> |
||||
</resources> |
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<color name="colorPrimary">#3F51B5</color> |
||||
<color name="colorPrimaryDark">#303F9F</color> |
||||
<color name="colorAccent">#FF4081</color> |
||||
</resources> |
@ -0,0 +1,6 @@
|
||||
<resources> |
||||
<!-- Default screen margins, per the Android Design guidelines. --> |
||||
<dimen name="activity_horizontal_margin">16dp</dimen> |
||||
<dimen name="activity_vertical_margin">16dp</dimen> |
||||
<dimen name="button_text_size">12sp</dimen> |
||||
</resources> |
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
|
||||
<string name="app_name">GnssLogger</string> |
||||
<string name="app_version">v1.4.0.0</string> |
||||
|
||||
<string name="title_settings">Settings</string> |
||||
<string name="title_log">Log</string> |
||||
<string name="title_device">Device</string> |
||||
<integer name="google_play_services_version">8487000</integer> |
||||
<string name="location_label">Location</string> |
||||
<string name="measurements_label">Measurements</string> |
||||
<string name="nav_msg_label">Navigation Messages</string> |
||||
<string name="gnss_status_label">GnssStatus</string> |
||||
<string name="nmea_label">Nmea</string> |
||||
<string name="help">HELP</string> |
||||
<string name="exit">Exit</string> |
||||
|
||||
</resources> |
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> |
||||
</style> |
||||
</resources> |
@ -0,0 +1,23 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules. |
||||
|
||||
buildscript { |
||||
repositories { |
||||
jcenter() |
||||
} |
||||
dependencies { |
||||
classpath 'com.android.tools.build:gradle:2.2.0' |
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong |
||||
// in the individual module build.gradle files |
||||
} |
||||
} |
||||
|
||||
allprojects { |
||||
repositories { |
||||
jcenter() |
||||
} |
||||
} |
||||
|
||||
task clean(type: Delete) { |
||||
delete rootProject.buildDir |
||||
} |
@ -0,0 +1,17 @@
|
||||
# Project-wide Gradle settings. |
||||
|
||||
# IDE (e.g. Android Studio) users: |
||||
# Gradle settings configured through the IDE *will override* |
||||
# any settings specified in this file. |
||||
|
||||
# For more details on how to configure your build environment visit |
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html |
||||
|
||||
# Specifies the JVM arguments used for the daemon process. |
||||
# The setting is particularly useful for tweaking memory settings. |
||||
org.gradle.jvmargs=-Xmx1536m |
||||
|
||||
# When configured, Gradle will run in incubating parallel mode. |
||||
# This option should only be used with decoupled projects. More details, visit |
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
||||
# org.gradle.parallel=true |
@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env bash |
||||
|
||||
############################################################################## |
||||
## |
||||
## Gradle start up script for UN*X |
||||
## |
||||
############################################################################## |
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
DEFAULT_JVM_OPTS="" |
||||
|
||||
APP_NAME="Gradle" |
||||
APP_BASE_NAME=`basename "$0"` |
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
||||
MAX_FD="maximum" |
||||
|
||||
warn ( ) { |
||||
echo "$*" |
||||
} |
||||
|
||||
die ( ) { |
||||
echo |
||||
echo "$*" |
||||
echo |
||||
exit 1 |
||||
} |
||||
|
||||
# OS specific support (must be 'true' or 'false'). |
||||
cygwin=false |
||||
msys=false |
||||
darwin=false |
||||
case "`uname`" in |
||||
CYGWIN* ) |
||||
cygwin=true |
||||
;; |
||||
Darwin* ) |
||||
darwin=true |
||||
;; |
||||
MINGW* ) |
||||
msys=true |
||||
;; |
||||
esac |
||||
|
||||
# Attempt to set APP_HOME |
||||
# Resolve links: $0 may be a link |
||||
PRG="$0" |
||||
# Need this for relative symlinks. |
||||
while [ -h "$PRG" ] ; do |
||||
ls=`ls -ld "$PRG"` |
||||
link=`expr "$ls" : '.*-> \(.*\)$'` |
||||
if expr "$link" : '/.*' > /dev/null; then |
||||
PRG="$link" |
||||
else |
||||
PRG=`dirname "$PRG"`"/$link" |
||||
fi |
||||
done |
||||
SAVED="`pwd`" |
||||
cd "`dirname \"$PRG\"`/" >/dev/null |
||||
APP_HOME="`pwd -P`" |
||||
cd "$SAVED" >/dev/null |
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
||||
|
||||
# Determine the Java command to use to start the JVM. |
||||
if [ -n "$JAVA_HOME" ] ; then |
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
||||
# IBM's JDK on AIX uses strange locations for the executables |
||||
JAVACMD="$JAVA_HOME/jre/sh/java" |
||||
else |
||||
JAVACMD="$JAVA_HOME/bin/java" |
||||
fi |
||||
if [ ! -x "$JAVACMD" ] ; then |
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
else |
||||
JAVACMD="java" |
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
|
||||
# Increase the maximum file descriptors if we can. |
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then |
||||
MAX_FD_LIMIT=`ulimit -H -n` |
||||
if [ $? -eq 0 ] ; then |
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then |
||||
MAX_FD="$MAX_FD_LIMIT" |
||||
fi |
||||
ulimit -n $MAX_FD |
||||
if [ $? -ne 0 ] ; then |
||||
warn "Could not set maximum file descriptor limit: $MAX_FD" |
||||
fi |
||||
else |
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" |
||||
fi |
||||
fi |
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock |
||||
if $darwin; then |
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" |
||||
fi |
||||
|
||||
# For Cygwin, switch paths to Windows format before running java |
||||
if $cygwin ; then |
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
||||
JAVACMD=`cygpath --unix "$JAVACMD"` |
||||
|
||||
# We build the pattern for arguments to be converted via cygpath |
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` |
||||
SEP="" |
||||
for dir in $ROOTDIRSRAW ; do |
||||
ROOTDIRS="$ROOTDIRS$SEP$dir" |
||||
SEP="|" |
||||
done |
||||
OURCYGPATTERN="(^($ROOTDIRS))" |
||||
# Add a user-defined pattern to the cygpath arguments |
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then |
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" |
||||
fi |
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
||||
i=0 |
||||
for arg in "$@" ; do |
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` |
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option |
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition |
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` |
||||
else |
||||
eval `echo args$i`="\"$arg\"" |
||||
fi |
||||
i=$((i+1)) |
||||
done |
||||
case $i in |
||||
(0) set -- ;; |
||||
(1) set -- "$args0" ;; |
||||
(2) set -- "$args0" "$args1" ;; |
||||
(3) set -- "$args0" "$args1" "$args2" ;; |
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; |
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; |
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; |
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; |
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; |
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; |
||||
esac |
||||
fi |
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules |
||||
function splitJvmOpts() { |
||||
JVM_OPTS=("$@") |
||||
} |
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS |
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" |
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off |
||||
@rem ########################################################################## |
||||
@rem |
||||
@rem Gradle startup script for Windows |
||||
@rem |
||||
@rem ########################################################################## |
||||
|
||||
@rem Set local scope for the variables with windows NT shell |
||||
if "%OS%"=="Windows_NT" setlocal |
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
set DEFAULT_JVM_OPTS= |
||||
|
||||
set DIRNAME=%~dp0 |
||||
if "%DIRNAME%" == "" set DIRNAME=. |
||||
set APP_BASE_NAME=%~n0 |
||||
set APP_HOME=%DIRNAME% |
||||
|
||||
@rem Find java.exe |
||||
if defined JAVA_HOME goto findJavaFromJavaHome |
||||
|
||||
set JAVA_EXE=java.exe |
||||
%JAVA_EXE% -version >NUL 2>&1 |
||||
if "%ERRORLEVEL%" == "0" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:findJavaFromJavaHome |
||||
set JAVA_HOME=%JAVA_HOME:"=% |
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
||||
|
||||
if exist "%JAVA_EXE%" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:init |
||||
@rem Get command-line arguments, handling Windowz variants |
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args |
||||
if "%@eval[2+2]" == "4" goto 4NT_args |
||||
|
||||
:win9xME_args |
||||
@rem Slurp the command line arguments. |
||||
set CMD_LINE_ARGS= |
||||
set _SKIP=2 |
||||
|
||||
:win9xME_args_slurp |
||||
if "x%~1" == "x" goto execute |
||||
|
||||
set CMD_LINE_ARGS=%* |
||||
goto execute |
||||
|
||||
:4NT_args |
||||
@rem Get arguments from the 4NT Shell from JP Software |
||||
set CMD_LINE_ARGS=%$ |
||||
|
||||
:execute |
||||
@rem Setup the command line |
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
||||
|
||||
@rem Execute Gradle |
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% |
||||
|
||||
:end |
||||
@rem End local scope for the variables with windows NT shell |
||||
if "%ERRORLEVEL%"=="0" goto mainEnd |
||||
|
||||
:fail |
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
||||
rem the _cmd.exe /c_ return code! |
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
||||
exit /b 1 |
||||
|
||||
:mainEnd |
||||
if "%OS%"=="Windows_NT" endlocal |
||||
|
||||
:omega |
@ -0,0 +1,10 @@
|
||||
## This file is automatically generated by Android Studio. |
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED! |
||||
# |
||||
# This file should *NOT* be checked into Version Control Systems, |
||||
# as it contains information specific to your local configuration. |
||||
# |
||||
# Location of the SDK. This is only used by Gradle. |
||||
# For customization when using a Version Control System, please read the |
||||
# header note. |
||||
sdk.dir=/media/build/master/prebuilts/fullsdk/linux |
Loading…
Reference in new issue