mirror of
https://github.com/barbeau/gpstest.git
synced 2025-12-05 18:46:30 -06:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90e0d9f9be | ||
|
|
80b6848a09 | ||
|
|
c5a3d684e6 | ||
|
|
f549508ad3 | ||
|
|
a3dfa50b99 | ||
|
|
640bd4b9a7 | ||
|
|
2b1ed93629 | ||
|
|
148b609e37 | ||
|
|
acea0e0249 | ||
|
|
9fd28d5a61 | ||
|
|
4ac38c380f | ||
|
|
3b23f9514b | ||
|
|
726481d50c | ||
|
|
c304bc8fdb | ||
|
|
6eaabe2f8c | ||
|
|
6994b33a8c | ||
|
|
25902ed60f | ||
|
|
1eb6ed9477 | ||
|
|
acc19cff01 | ||
|
|
8a700e987e | ||
|
|
4e7c77fbb2 | ||
|
|
91378d5f79 | ||
|
|
5d4a0f9a60 | ||
|
|
8f07afeb83 | ||
|
|
2196e66428 | ||
|
|
8c050491a3 | ||
|
|
b54c203e1b | ||
|
|
b7b3fbc66e | ||
|
|
bf0bb3a54d | ||
|
|
4292ea40da | ||
|
|
9e8f9734be | ||
|
|
a057fe448f | ||
|
|
aa8a6ff4fe | ||
|
|
b069b82802 | ||
|
|
1dab959ba4 | ||
|
|
8c258b0cca | ||
|
|
221e46cb30 | ||
|
|
58a643e1f0 |
14
.github/dependabot.yml
vendored
Normal file
14
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
commit-message:
|
||||
prefix: "actions-update"
|
||||
labels: [ 'enhancement' ]
|
||||
schedule:
|
||||
interval: "daily"
|
||||
groups:
|
||||
actions-dependencies:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "*"
|
||||
4
.github/stale.yml
vendored
4
.github/stale.yml
vendored
@@ -1,7 +1,7 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 200
|
||||
daysUntilStale: 400
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 200
|
||||
daysUntilClose: 400
|
||||
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
|
||||
155
.github/workflows/android.yml
vendored
155
.github/workflows/android.yml
vendored
@@ -12,27 +12,146 @@ on:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
test:
|
||||
runs-on: macos-latest
|
||||
unit-test:
|
||||
name: Perform checks
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (audit mode)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
|
||||
- name: Setup Gradle and cache
|
||||
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
|
||||
with:
|
||||
gradle-version: wrapper
|
||||
|
||||
- name: Run checks
|
||||
run: ./gradlew check
|
||||
|
||||
- name: Upload SARIF report
|
||||
uses: github/codeql-action/upload-sarif@fe4161a26a8629af62121b670040955b330f9af2 # v3.29.5
|
||||
if: success() || failure()
|
||||
with:
|
||||
sarif_file: GPSTest/build/reports/lint-results-googleDebug.sarif
|
||||
category: lint
|
||||
|
||||
build:
|
||||
name: Build debug APK
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (audit mode)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Android SDK
|
||||
uses: android-actions/setup-android@9fc6c4e9069bf8d3d10b2204b1fb8f6ef7065407 # v3.2.2
|
||||
with:
|
||||
log-accepted-android-sdk-licenses: false
|
||||
|
||||
- name: Setup Gradle and cache
|
||||
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
|
||||
with:
|
||||
gradle-version: wrapper
|
||||
cache-read-only: true
|
||||
|
||||
- name: Build app
|
||||
run: ./gradlew assembleDebug --stacktrace
|
||||
|
||||
- name: Upload APKs
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
with:
|
||||
name: apks
|
||||
path: |
|
||||
GPSTest/build/outputs/apk/
|
||||
wear/build/outputs/apk/
|
||||
|
||||
instrumentation-test:
|
||||
name: Run instrumented tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
api-level: [24, 29]
|
||||
api-level: [24, 29, 33]
|
||||
target: [default, google_apis]
|
||||
tasks: [connectedGoogleDebugAndroidTest, connectedOsmdroidDebugAndroidTest]
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Harden the runner (audit mode)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: 'adopt'
|
||||
- name: Checkout the code
|
||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||
|
||||
- name: run tests
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
target: ${{ matrix.target }}
|
||||
arch: x86_64
|
||||
profile: Nexus 6
|
||||
script: ./gradlew test check connectedCheck -x lint --stacktrace
|
||||
- name: Enable KVM
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # v5.1.0
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle and cache
|
||||
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
|
||||
with:
|
||||
gradle-version: wrapper
|
||||
cache-read-only: true
|
||||
|
||||
- name: Configure AVD cache
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
id: avd-cache
|
||||
with:
|
||||
path: |
|
||||
~/.android/avd/*
|
||||
~/.android/adb*
|
||||
key: avd-${{ matrix.target }}-${{ matrix.api-level }}
|
||||
|
||||
- name: Create AVD and generate snapshot for caching
|
||||
if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||
uses: reactivecircus/android-emulator-runner@b530d96654c385303d652368551fb075bc2f0b6b # v2.35.0
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
target: ${{ matrix.target }}
|
||||
force-avd-creation: false
|
||||
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
|
||||
disable-animations: false
|
||||
script: echo "Generated AVD snapshot for caching."
|
||||
arch: x86_64
|
||||
profile: Nexus 6
|
||||
|
||||
- name: Run instrumentation tests
|
||||
uses: reactivecircus/android-emulator-runner@b530d96654c385303d652368551fb075bc2f0b6b # v2.35.0
|
||||
with:
|
||||
api-level: ${{ matrix.api-level }}
|
||||
target: ${{ matrix.target }}
|
||||
force-avd-creation: false
|
||||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
|
||||
disable-animations: true
|
||||
script: |
|
||||
adb wait-for-device
|
||||
./gradlew ${{ matrix.tasks }} -x lint --stacktrace && killall -INT crashpad_handler || true
|
||||
arch: x86_64
|
||||
profile: Nexus 6
|
||||
|
||||
2
.github/workflows/transifex.yml
vendored
2
.github/workflows/transifex.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6
|
||||
- name: Run script to push English strings to Transifex
|
||||
run: |
|
||||
chmod +x ./scripts/push-to-transifex.sh
|
||||
|
||||
170
.gitignore
vendored
170
.gitignore
vendored
@@ -1,5 +1,167 @@
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/android,androidstudio
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=android,androidstudio
|
||||
|
||||
### Android ###
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Log/OS Files
|
||||
*.log
|
||||
|
||||
# Android Studio generated files and folders
|
||||
captures/
|
||||
.externalNativeBuild/
|
||||
.cxx/
|
||||
*.apk
|
||||
output.json
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.DS_Store
|
||||
.idea/
|
||||
misc.xml
|
||||
deploymentTargetDropDown.xml
|
||||
render.experimental.xml
|
||||
|
||||
# Keystore files
|
||||
*.jks
|
||||
*.keystore
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
google-services.json
|
||||
|
||||
# Android Profiling
|
||||
*.hprof
|
||||
|
||||
### Android Patch ###
|
||||
gen-external-apklibs
|
||||
|
||||
# Replacement of .externalNativeBuild directories introduced
|
||||
# with Android Studio 3.5.
|
||||
|
||||
### AndroidStudio ###
|
||||
# Covers files to be ignored for android development using Android Studio.
|
||||
|
||||
# Built application files
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
|
||||
# Gradle files
|
||||
.gradle
|
||||
|
||||
# Signing files
|
||||
.signing/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
|
||||
# Android Studio
|
||||
/*/build/
|
||||
/*/local.properties
|
||||
/*/out
|
||||
/*/*/build
|
||||
/*/*/production
|
||||
.navigation/
|
||||
*.ipr
|
||||
*~
|
||||
*.swp
|
||||
|
||||
# Keystore files
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
# google-services.json
|
||||
|
||||
# Android Patch
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
|
||||
# NDK
|
||||
obj/
|
||||
|
||||
# IntelliJ IDEA
|
||||
*.iws
|
||||
/out/
|
||||
|
||||
# User-specific configurations
|
||||
.idea/caches/
|
||||
.idea/libraries/
|
||||
.idea/shelf/
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/.name
|
||||
.idea/compiler.xml
|
||||
.idea/copyright/profiles_settings.xml
|
||||
.idea/encodings.xml
|
||||
.idea/misc.xml
|
||||
.idea/modules.xml
|
||||
.idea/scopes/scope_settings.xml
|
||||
.idea/dictionaries
|
||||
.idea/vcs.xml
|
||||
.idea/jsLibraryMappings.xml
|
||||
.idea/datasources.xml
|
||||
.idea/dataSources.ids
|
||||
.idea/sqlDataSources.xml
|
||||
.idea/dynamic.xml
|
||||
.idea/uiDesigner.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/gradle.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/navEditor.xml
|
||||
|
||||
# Legacy Eclipse project files
|
||||
.classpath
|
||||
.project
|
||||
.cproject
|
||||
.settings/
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
|
||||
hs_err_pid*
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
### AndroidStudio Patch ###
|
||||
|
||||
!/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/android,androidstudio
|
||||
2
FAQ.md
2
FAQ.md
@@ -77,7 +77,7 @@ Android 1.5 and up, in its simplest form. More advanced versions with an update
|
||||
* **Start/Stop** - Start/stop the GPS hardware
|
||||
* **Send Location** - After a latitude and longitude has been acquired, you can share this info
|
||||
* **Inject Time** - Injects Time assistance data for GPS into the platform, using information from a [Network Time Protocol (NTP)](http://support.ntp.org/bin/view/Main/WebHome) server. Note that some devices don't use an NTP server for time data - if this is your device, you'll see a message saying "Platform does not support injecting time data".
|
||||
* **Inject PSDS Data** - Injects Predicted Satellite Data Service (PSDS) assistance data for GNSS into the platform, using information from a PSDS server. Note that some devices don't use PSDS for assistance data - if this is your device, you'll see a message saying "Platform does not support injecting PSDS data". PSDS is the generic term for products like [XTRA assistance data](http://goo.gl/3RjWX).
|
||||
* **Inject PSDS Data** - Injects Predicted Satellite Data Service (PSDS) assistance data for GNSS into the platform, using information from a PSDS server. Note that some devices don't use PSDS for assistance data - if this is your device, you'll see a message saying "Platform does not support injecting PSDS data". PSDS is the generic term for products like [XTRA assistance data](https://www.qualcomm.com/news/releases/2007/02/qualcomm-introduces-gpsonextra-assistance-expand-capabilities-standalone).
|
||||
* **Clear Aiding Data** - Clears all assistance data used for GPS, including NTP and PSDS/XTRA data (Note: if you select this option to fix broken GPS on your device, for GPS to work again you may need to ‘Inject Time’ and ‘Inject PSDS’ data). Note that some devices don't support clearing assistance data - if this is your device, you'll see a message saying "Platform does not support deleting aiding data". You may also see a large delay until your device acquires a fix again, so please use this feature with caution.
|
||||
* **Settings** - Set map tile type
|
||||
|
||||
|
||||
@@ -2,17 +2,18 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'dagger.hilt.android.plugin'
|
||||
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdkVersion 31
|
||||
targetSdkVersion 34
|
||||
multiDexEnabled true
|
||||
// versionCode scheme - first two digits are minSdkVersion, last three digits are build number
|
||||
versionCode 24097
|
||||
versionName "3.10.3"
|
||||
versionCode 24099
|
||||
versionName "3.10.5"
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
@@ -55,7 +56,8 @@ android {
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
disable 'MissingTranslation', 'ExtraTranslation'
|
||||
sarifReport true
|
||||
disable 'MissingTranslation', 'ExtraTranslation', 'StringFormatInvalid'
|
||||
}
|
||||
|
||||
if (project.hasProperty("secure.properties")
|
||||
@@ -109,11 +111,11 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8
|
||||
jvmTarget = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
testOptions {
|
||||
@@ -130,11 +132,16 @@ android {
|
||||
viewBinding true
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
// Gradle automatically adds 'android.test.runner' as a dependency.
|
||||
useLibrary 'android.test.runner'
|
||||
|
||||
useLibrary 'android.test.base'
|
||||
useLibrary 'android.test.mock'
|
||||
namespace 'com.android.gpstest'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -159,7 +166,7 @@ dependencies {
|
||||
// Uploading device properties on user request
|
||||
implementation 'androidx.core:core-ktx:1.10.0-rc01'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
|
||||
implementation 'commons-io:commons-io:2.8.0'
|
||||
implementation 'commons-io:commons-io:2.14.0'
|
||||
|
||||
// Share dialog
|
||||
implementation 'androidx.viewpager2:viewpager2:1.0.0'
|
||||
|
||||
@@ -150,7 +150,7 @@ class CarrierFreqUtilsTest {
|
||||
|
||||
// Beidou
|
||||
|
||||
// Beidou B1
|
||||
// Beidou B1I
|
||||
val beidouB1 = SatelliteStatus(1,
|
||||
GnssType.BEIDOU,
|
||||
30f,
|
||||
@@ -163,22 +163,7 @@ class CarrierFreqUtilsTest {
|
||||
beidouB1.carrierFrequencyHz = 1561098000.0
|
||||
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(beidouB1)
|
||||
assertEquals("B1", label)
|
||||
|
||||
// Beidou B1-2
|
||||
val beidouB1_2 = SatelliteStatus(1,
|
||||
GnssType.BEIDOU,
|
||||
30f,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
72f,
|
||||
25f);
|
||||
beidouB1_2.hasCarrierFrequency = true
|
||||
beidouB1_2.carrierFrequencyHz = 1589742000.0
|
||||
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(beidouB1_2)
|
||||
assertEquals("B1-2", label)
|
||||
assertEquals("B1I", label)
|
||||
|
||||
// Beidou B1C
|
||||
val beidouB1c = SatelliteStatus(1,
|
||||
@@ -210,21 +195,6 @@ class CarrierFreqUtilsTest {
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(beidouB1c202)
|
||||
assertEquals("B1C", label)
|
||||
|
||||
// Beidou B2
|
||||
val beidouB2 = SatelliteStatus(1,
|
||||
GnssType.BEIDOU,
|
||||
30f,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
72f,
|
||||
25f);
|
||||
beidouB2.hasCarrierFrequency = true
|
||||
beidouB2.carrierFrequencyHz = 1207140000.0
|
||||
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(beidouB2)
|
||||
assertEquals("B2", label)
|
||||
|
||||
// Beidou B2a
|
||||
val beidouB2a = SatelliteStatus(1,
|
||||
GnssType.BEIDOU,
|
||||
@@ -240,7 +210,23 @@ class CarrierFreqUtilsTest {
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(beidouB2a)
|
||||
assertEquals("B2a", label)
|
||||
|
||||
// Beidou B3
|
||||
|
||||
// Beidou B2b
|
||||
val beidouB2b = SatelliteStatus(1,
|
||||
GnssType.BEIDOU,
|
||||
30f,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
72f,
|
||||
25f);
|
||||
beidouB2b.hasCarrierFrequency = true
|
||||
beidouB2b.carrierFrequencyHz = 1207140000.0
|
||||
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(beidouB2b)
|
||||
assertEquals("B2b", label)
|
||||
|
||||
// Beidou B3I
|
||||
val beidouB3 = SatelliteStatus(1,
|
||||
GnssType.BEIDOU,
|
||||
30f,
|
||||
@@ -253,10 +239,25 @@ class CarrierFreqUtilsTest {
|
||||
beidouB3.carrierFrequencyHz = 1268520000.0
|
||||
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(beidouB3)
|
||||
assertEquals("B3", label)
|
||||
assertEquals("B3I", label)
|
||||
|
||||
// IRNSS
|
||||
|
||||
// IRNSS L1
|
||||
val irnssL1 = SatelliteStatus(1,
|
||||
GnssType.IRNSS,
|
||||
30f,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
72f,
|
||||
25f);
|
||||
irnssL1.hasCarrierFrequency = true
|
||||
irnssL1.carrierFrequencyHz = 1575420000.0
|
||||
|
||||
label = CarrierFreqUtils.getCarrierFrequencyLabel(irnssL1)
|
||||
assertEquals("L1", label)
|
||||
|
||||
// IRNSS L5
|
||||
val irnssL5 = SatelliteStatus(1,
|
||||
GnssType.IRNSS,
|
||||
@@ -732,7 +733,7 @@ class CarrierFreqUtilsTest {
|
||||
fun testIsPrimaryCarrier() {
|
||||
assertTrue(CarrierFreqUtils.isPrimaryCarrier("L1"))
|
||||
assertTrue(CarrierFreqUtils.isPrimaryCarrier("E1"))
|
||||
assertTrue(CarrierFreqUtils.isPrimaryCarrier("B1"))
|
||||
assertTrue(CarrierFreqUtils.isPrimaryCarrier("B1I"))
|
||||
assertTrue(CarrierFreqUtils.isPrimaryCarrier("B1C"))
|
||||
assertTrue(CarrierFreqUtils.isPrimaryCarrier("L1-C"))
|
||||
|
||||
|
||||
@@ -20,7 +20,10 @@ import android.location.Location
|
||||
import androidx.test.InstrumentationRegistry.getTargetContext
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import com.android.gpstest.library.util.IOUtils
|
||||
import junit.framework.Assert.*
|
||||
import junit.framework.Assert.assertEquals
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertNull
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package com.android.gpstest;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getTargetContext;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
|
||||
@@ -27,10 +31,6 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getTargetContext;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class LocationUtilsTest {
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.android.gpstest;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
|
||||
|
||||
import com.android.gpstest.library.util.MathUtils;
|
||||
@@ -24,8 +26,6 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
@RunWith(AndroidJUnit4ClassRunner.class)
|
||||
public class MathUtilsAndroidTest {
|
||||
|
||||
|
||||
@@ -15,14 +15,21 @@
|
||||
*/
|
||||
package com.android.gpstest
|
||||
|
||||
import android.location.GnssMeasurement.*
|
||||
import android.location.GnssMeasurement.ADR_STATE_CYCLE_SLIP
|
||||
import android.location.GnssMeasurement.ADR_STATE_HALF_CYCLE_REPORTED
|
||||
import android.location.GnssMeasurement.ADR_STATE_HALF_CYCLE_RESOLVED
|
||||
import android.location.GnssMeasurement.ADR_STATE_RESET
|
||||
import android.location.GnssMeasurement.ADR_STATE_UNKNOWN
|
||||
import android.location.GnssMeasurement.ADR_STATE_VALID
|
||||
import android.os.Build
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import com.android.gpstest.library.model.GnssType
|
||||
import com.android.gpstest.library.model.SatelliteStatus
|
||||
import com.android.gpstest.library.model.SbasType
|
||||
import com.android.gpstest.library.util.SatelliteUtils
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
|
||||
@@ -17,19 +17,27 @@
|
||||
package com.android.gpstest
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.preference.PreferenceManager
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.test.InstrumentationRegistry
|
||||
import androidx.test.InstrumentationRegistry.getTargetContext
|
||||
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
|
||||
import com.android.gpstest.library.data.*
|
||||
import com.android.gpstest.library.data.LocationRepository
|
||||
import com.android.gpstest.library.data.SharedAntennaManager
|
||||
import com.android.gpstest.library.data.SharedGnssMeasurementManager
|
||||
import com.android.gpstest.library.data.SharedGnssStatusManager
|
||||
import com.android.gpstest.library.data.SharedLocationManager
|
||||
import com.android.gpstest.library.data.SharedNavMessageManager
|
||||
import com.android.gpstest.library.data.SharedNmeaManager
|
||||
import com.android.gpstest.library.data.SharedSensorManager
|
||||
import com.android.gpstest.library.model.GnssType
|
||||
import com.android.gpstest.library.model.SbasType
|
||||
import com.android.gpstest.library.ui.SignalInfoViewModel
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@@ -35,22 +35,30 @@ import com.android.gpstest.Application
|
||||
import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.R
|
||||
import com.android.gpstest.library.data.LocationRepository
|
||||
import com.android.gpstest.library.util.MathUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtil
|
||||
import com.android.gpstest.map.MapConstants
|
||||
import com.android.gpstest.map.MapViewModelController
|
||||
import com.android.gpstest.map.MapViewModelController.MapInterface
|
||||
import com.android.gpstest.map.OnMapClickListener
|
||||
import com.android.gpstest.util.MapUtils
|
||||
import com.android.gpstest.library.util.MathUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtil
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import com.google.android.gms.maps.CameraUpdateFactory
|
||||
import com.google.android.gms.maps.GoogleMap
|
||||
import com.google.android.gms.maps.GoogleMap.*
|
||||
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener
|
||||
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener
|
||||
import com.google.android.gms.maps.GoogleMap.OnMyLocationButtonClickListener
|
||||
import com.google.android.gms.maps.LocationSource
|
||||
import com.google.android.gms.maps.LocationSource.OnLocationChangedListener
|
||||
import com.google.android.gms.maps.SupportMapFragment
|
||||
import com.google.android.gms.maps.model.*
|
||||
import com.google.android.gms.maps.model.CameraPosition
|
||||
import com.google.android.gms.maps.model.LatLng
|
||||
import com.google.android.gms.maps.model.MapStyleOptions
|
||||
import com.google.android.gms.maps.model.Marker
|
||||
import com.google.android.gms.maps.model.MarkerOptions
|
||||
import com.google.android.gms.maps.model.Polyline
|
||||
import com.google.android.gms.maps.model.PolylineOptions
|
||||
import com.google.maps.android.SphericalUtil
|
||||
import com.google.maps.android.ktx.awaitMap
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
<!-- Required for foreground services on P+ -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<!-- Required for notifications on T+ -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<!-- Required for the location service when targeting API 34 and up -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:name=".Application"
|
||||
android:label="@string/app_name"
|
||||
@@ -52,7 +58,8 @@
|
||||
<activity
|
||||
android:name=".ui.Preferences"
|
||||
android:label="@string/pref_title"
|
||||
android:exported="true">
|
||||
android:exported="true"
|
||||
android:noHistory="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
@@ -50,7 +50,12 @@ import com.android.gpstest.library.data.LocationRepository
|
||||
import com.android.gpstest.library.model.SatelliteGroup
|
||||
import com.android.gpstest.library.model.SatelliteMetadata
|
||||
import com.android.gpstest.library.util.FormatUtils.toNotificationTitle
|
||||
import com.android.gpstest.library.util.IOUtils.*
|
||||
import com.android.gpstest.library.util.IOUtils.deleteOldFiles
|
||||
import com.android.gpstest.library.util.IOUtils.forcePsdsInjection
|
||||
import com.android.gpstest.library.util.IOUtils.forceTimeInjection
|
||||
import com.android.gpstest.library.util.IOUtils.writeMeasurementToLogcat
|
||||
import com.android.gpstest.library.util.IOUtils.writeNavMessageToAndroidStudio
|
||||
import com.android.gpstest.library.util.IOUtils.writeNmeaToAndroidStudio
|
||||
import com.android.gpstest.library.util.LibUIUtils.toNotificationSummary
|
||||
import com.android.gpstest.library.util.PreferenceUtil
|
||||
import com.android.gpstest.library.util.PreferenceUtil.isCsvLoggingEnabled
|
||||
@@ -73,13 +78,18 @@ import com.android.gpstest.library.util.SatelliteUtil.toSatelliteStatus
|
||||
import com.android.gpstest.library.util.SatelliteUtils
|
||||
import com.android.gpstest.ui.MainActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Service tracks location, logs to files, and shows a notification to the user.
|
||||
|
||||
@@ -10,9 +10,12 @@ import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.Downloads;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.android.gpstest.Application;
|
||||
import com.android.gpstest.R;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
|
||||
@@ -219,7 +219,7 @@ public class CsvFileLogger extends BaseFileLogger implements FileLogger {
|
||||
int i = 0;
|
||||
for (SatelliteStatus s : statuses) {
|
||||
try {
|
||||
writeStatusToFile(s, location != null ? location.getTime() : 0, i, statuses.size());
|
||||
writeStatusToFile(s, location != null ? location.getTime() : 0, statuses.size(), i);
|
||||
} catch (IOException e) {
|
||||
logException(Application.Companion.getApp().getString(R.string.error_writing_file), e);
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ import com.android.gpstest.chart.DistanceValueFormatter;
|
||||
import com.android.gpstest.library.model.AvgError;
|
||||
import com.android.gpstest.library.model.MeasuredError;
|
||||
import com.android.gpstest.library.util.IOUtils;
|
||||
import com.android.gpstest.library.util.LibUIUtils;
|
||||
import com.android.gpstest.library.util.MathUtils;
|
||||
import com.android.gpstest.library.util.PreferenceUtils;
|
||||
import com.android.gpstest.library.util.LibUIUtils;
|
||||
import com.android.gpstest.util.UIUtils;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
|
||||
@@ -75,14 +75,14 @@ import com.android.gpstest.util.UIUtils
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial
|
||||
import com.google.zxing.integration.android.IntentIntegrator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.exitProcess
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : AppCompatActivity(), NavigationDrawerCallbacks {
|
||||
@@ -337,7 +337,7 @@ class MainActivity : AppCompatActivity(), NavigationDrawerCallbacks {
|
||||
|
||||
private fun requestPermissionAndInit(activity: Activity) {
|
||||
if (PermissionUtils.hasGrantedPermissions(activity, PermissionUtils.REQUIRED_PERMISSIONS)) {
|
||||
init()
|
||||
initGnss()
|
||||
} else {
|
||||
// Request permissions from the user
|
||||
ActivityCompat.requestPermissions(
|
||||
@@ -349,20 +349,20 @@ class MainActivity : AppCompatActivity(), NavigationDrawerCallbacks {
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int, permissions: Array<String>, grantResults: IntArray
|
||||
requestCode: Int, permissions: Array<String>, grantResults: IntArray,
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == PermissionUtils.LOCATION_PERMISSION_REQUEST) {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
userDeniedPermission = false
|
||||
init()
|
||||
initGnss()
|
||||
} else {
|
||||
userDeniedPermission = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
private fun initGnss() {
|
||||
val locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
|
||||
val provider = locationManager.getProvider(LocationManager.GPS_PROVIDER)
|
||||
if (provider == null) {
|
||||
@@ -928,6 +928,5 @@ class MainActivity : AppCompatActivity(), NavigationDrawerCallbacks {
|
||||
companion object {
|
||||
private const val TAG = "GpsTestActivity"
|
||||
private const val SECONDS_TO_MILLISECONDS = 1000
|
||||
private const val GPS_RESUME = "gps_resume"
|
||||
}
|
||||
}
|
||||
@@ -15,29 +15,51 @@
|
||||
*/
|
||||
package com.android.gpstest.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.content.pm.PackageManager
|
||||
import android.location.LocationManager
|
||||
import android.os.Build.VERSION
|
||||
import android.os.Build.VERSION_CODES
|
||||
import android.os.Bundle
|
||||
import android.preference.*
|
||||
import android.preference.CheckBoxPreference
|
||||
import android.preference.EditTextPreference
|
||||
import android.preference.ListPreference
|
||||
import android.preference.Preference
|
||||
import android.preference.Preference.OnPreferenceChangeListener
|
||||
import android.preference.PreferenceActivity
|
||||
import android.preference.PreferenceCategory
|
||||
import android.text.InputType
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.app.ActivityCompat
|
||||
import com.android.gpstest.Application.Companion.app
|
||||
import com.android.gpstest.Application.Companion.localeManager
|
||||
import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.BuildConfig
|
||||
import com.android.gpstest.R
|
||||
import com.android.gpstest.library.util.PermissionUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtil.enableMeasurementsPref
|
||||
import com.android.gpstest.library.util.SatelliteUtils
|
||||
import com.android.gpstest.library.util.LibUIUtils.resetActivityTitle
|
||||
import com.android.gpstest.library.util.PermissionUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtil
|
||||
import com.android.gpstest.library.util.PreferenceUtil.enableMeasurementsPref
|
||||
import com.android.gpstest.library.util.PreferenceUtil.enableNavMessagesPref
|
||||
import com.android.gpstest.library.util.PreferenceUtils
|
||||
import com.android.gpstest.library.util.SatelliteUtils
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Preferences : PreferenceActivity(), OnSharedPreferenceChangeListener {
|
||||
var forceFullGnssMeasurements: CheckBoxPreference? = null
|
||||
@@ -52,6 +74,8 @@ class Preferences : PreferenceActivity(), OnSharedPreferenceChangeListener {
|
||||
|
||||
var language: ListPreference? = null
|
||||
|
||||
var chkShowNotification: CheckBoxPreference? = null
|
||||
var chkRunInBackground: CheckBoxPreference? = null
|
||||
var chkLogFileNmea: CheckBoxPreference? = null
|
||||
var chkLogFileNavMessages: CheckBoxPreference? = null
|
||||
var chkLogFileMeasurements: CheckBoxPreference? = null
|
||||
@@ -181,6 +205,8 @@ class Preferences : PreferenceActivity(), OnSharedPreferenceChangeListener {
|
||||
chkAsNavMessages = findPreference(getString(R.string.pref_key_as_navigation_message_output)) as CheckBoxPreference
|
||||
chkAsNavMessages?.isEnabled = enableNavMessagesPref(app, prefs)
|
||||
|
||||
initNotificationPermissionDialog()
|
||||
|
||||
prefs.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
@@ -287,4 +313,186 @@ class Preferences : PreferenceActivity(), OnSharedPreferenceChangeListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the dialog for notification permissions, which is required for
|
||||
* notifications, background execution and logging.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private fun initNotificationPermissionDialog() {
|
||||
chkShowNotification =
|
||||
findPreference(getString(R.string.pref_key_show_notification)) as CheckBoxPreference
|
||||
if (VERSION.SDK_INT < VERSION_CODES.TIRAMISU) {
|
||||
// Notifications are always shown on Android 12 and lower
|
||||
chkShowNotification?.isEnabled = false
|
||||
PreferenceUtils.saveBoolean(
|
||||
getString(R.string.pref_key_show_notification),
|
||||
true,
|
||||
prefs
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Permissions for notifications are used in place of a user-defined setting. This workflow
|
||||
// supports users that have installed an update, who will already have permissions granted.
|
||||
// Additionally, revoking notification permissions seems to be the only way to disable
|
||||
// user-facing notifications for the foreground service, because they are required.
|
||||
PreferenceUtils.saveBoolean(
|
||||
getString(R.string.pref_key_show_notification),
|
||||
PermissionUtils.hasGrantedNotificationPermissions(this),
|
||||
prefs
|
||||
)
|
||||
|
||||
chkRunInBackground =
|
||||
findPreference(getString(R.string.pref_key_gnss_background)) as CheckBoxPreference
|
||||
chkLogFileNmea =
|
||||
findPreference(getString(R.string.pref_key_file_nmea_output)) as CheckBoxPreference
|
||||
chkLogFileNavMessages =
|
||||
findPreference(getString(R.string.pref_key_file_navigation_message_output)) as CheckBoxPreference
|
||||
chkLogFileMeasurements =
|
||||
findPreference(getString(R.string.pref_key_file_measurement_output)) as CheckBoxPreference
|
||||
chkLogFileLocation =
|
||||
findPreference(getString(R.string.pref_key_file_location_output)) as CheckBoxPreference
|
||||
chkLogFileAntennaJson =
|
||||
findPreference(getString(R.string.pref_key_file_antenna_output_json)) as CheckBoxPreference
|
||||
chkLogFileAntennaCsv =
|
||||
findPreference(getString(R.string.pref_key_file_antenna_output_csv)) as CheckBoxPreference
|
||||
val prefsThatNeedNotificationPermissions = listOf(
|
||||
chkShowNotification,
|
||||
chkRunInBackground,
|
||||
chkLogFileNmea,
|
||||
chkLogFileNavMessages,
|
||||
chkLogFileMeasurements,
|
||||
chkLogFileLocation,
|
||||
chkLogFileAntennaJson,
|
||||
chkLogFileAntennaCsv
|
||||
)
|
||||
prefsThatNeedNotificationPermissions.forEach {
|
||||
it?.onPreferenceChangeListener =
|
||||
OnPreferenceChangeListener { preference, newValue ->
|
||||
if (newValue as Boolean && !PermissionUtils.hasGrantedNotificationPermissions(
|
||||
this
|
||||
)
|
||||
) {
|
||||
// User must have granted notification permissions first
|
||||
createNotificationPermissionDialog(this).show()
|
||||
// Reject change to setting by returning false
|
||||
return@OnPreferenceChangeListener false
|
||||
} else {
|
||||
if (preference == chkShowNotification && !newValue &&
|
||||
(PreferenceUtil.runInBackground(
|
||||
this,
|
||||
prefs
|
||||
) || PreferenceUtil.isFileLoggingEnabled(this, prefs))
|
||||
) {
|
||||
// Don't let the user disable notifications if background execution or logging is enabled
|
||||
createCanNotDisableSettingDialog(this).show()
|
||||
// Reject change to setting by returning false
|
||||
return@OnPreferenceChangeListener false
|
||||
}
|
||||
|
||||
if (preference == chkShowNotification && !newValue) {
|
||||
// If the user disabled the notification setting prompt them to restart app
|
||||
createRestartApplicationDialog(this).show()
|
||||
return@OnPreferenceChangeListener false
|
||||
}
|
||||
|
||||
// Accept change to setting by returning true
|
||||
return@OnPreferenceChangeListener true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(VERSION_CODES.TIRAMISU)
|
||||
fun createNotificationPermissionDialog(activity: Activity): Dialog {
|
||||
val view = activity.layoutInflater.inflate(R.layout.notification_permissions_dialog, null)
|
||||
val textView = view.findViewById<TextView>(R.id.notification_permission_instructions)
|
||||
textView.text = getString(R.string.notification_permission_required_dialog_text)
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.notification_permission_required_dialog_title)
|
||||
.setCancelable(false)
|
||||
.setView(view)
|
||||
.setPositiveButton(
|
||||
R.string.ok
|
||||
) { _: DialogInterface?, _: Int -> requestNotificationPermission() }
|
||||
.setNegativeButton(R.string.cancel) { _: DialogInterface?, _: Int -> }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
@RequiresApi(VERSION_CODES.TIRAMISU)
|
||||
fun createCanNotDisableSettingDialog(activity: Activity): Dialog {
|
||||
val view = activity.layoutInflater.inflate(R.layout.notification_permissions_dialog, null)
|
||||
val textView = view.findViewById<TextView>(R.id.notification_permission_instructions)
|
||||
textView.text = getString(R.string.can_not_disable_setting_dialog_text)
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.notification_permission_required_dialog_title)
|
||||
.setCancelable(false)
|
||||
.setView(view)
|
||||
.setPositiveButton(
|
||||
R.string.ok
|
||||
) { _: DialogInterface?, _: Int -> requestNotificationPermission() }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
@RequiresApi(VERSION_CODES.TIRAMISU)
|
||||
fun createRestartApplicationDialog(activity: Activity): Dialog {
|
||||
val view = activity.layoutInflater.inflate(R.layout.notification_permissions_dialog, null)
|
||||
val textView = view.findViewById<TextView>(R.id.notification_permission_instructions)
|
||||
textView.text = getString(R.string.need_to_restart_application_dialog_text)
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
.setTitle(R.string.need_to_restart_application_dialog_title)
|
||||
.setCancelable(false)
|
||||
.setView(view)
|
||||
.setPositiveButton(
|
||||
R.string.ok
|
||||
) { _: DialogInterface?, _: Int -> revokeNotificationPermissionAndRestartApplication() }
|
||||
.setNegativeButton(R.string.cancel) { _: DialogInterface?, _: Int -> }
|
||||
return builder.create()
|
||||
}
|
||||
|
||||
@RequiresApi(api = VERSION_CODES.TIRAMISU)
|
||||
private fun requestNotificationPermission() {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(PermissionUtils.getNotificationPermission()),
|
||||
PermissionUtils.NOTIFICATION_PERMISSION_REQUEST
|
||||
)
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int, permissions: Array<String>, grantResults: IntArray,
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == PermissionUtils.NOTIFICATION_PERMISSION_REQUEST) {
|
||||
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// Notification permission granted - change the setting in the Preferences UI
|
||||
// The notification will automatically be posted by the service
|
||||
PreferenceUtils.saveBoolean(
|
||||
getString(R.string.pref_key_show_notification),
|
||||
true,
|
||||
prefs
|
||||
)
|
||||
recreate()
|
||||
} else {
|
||||
// Prompt the user to grant permissions again
|
||||
createNotificationPermissionDialog(this).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(VERSION_CODES.TIRAMISU)
|
||||
private fun Context.revokeNotificationPermissionAndRestartApplication() {
|
||||
revokeSelfPermissionOnKill(Manifest.permission.POST_NOTIFICATIONS)
|
||||
PreferenceUtils.saveBoolean(getString(R.string.pref_key_show_notification), false, prefs)
|
||||
|
||||
Executors.newSingleThreadScheduledExecutor().schedule({
|
||||
val intent = packageManager.getLaunchIntentForPackage(packageName)
|
||||
val componentName = intent?.component
|
||||
val mainIntent = Intent.makeRestartActivityTask(componentName)
|
||||
startActivity(mainIntent)
|
||||
Runtime.getRuntime().exit(0)
|
||||
}, 200, TimeUnit.MILLISECONDS)
|
||||
}
|
||||
}
|
||||
@@ -40,9 +40,9 @@ class ShareDialogFragment : DialogFragment() {
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val view = activity!!.layoutInflater.inflate(R.layout.share, null)
|
||||
val view = requireActivity().layoutInflater.inflate(R.layout.share, null)
|
||||
setRetainInstance(true)
|
||||
val builder = AlertDialog.Builder(activity!!)
|
||||
val builder = AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.share)
|
||||
.setView(view)
|
||||
.setNeutralButton(R.string.main_help_close) { dialog, _ -> }
|
||||
|
||||
@@ -18,8 +18,8 @@ import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.R
|
||||
import com.android.gpstest.library.model.CoordinateType
|
||||
import com.android.gpstest.library.util.IOUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtils
|
||||
import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtils
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.android.gpstest.ui.share
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@@ -17,7 +16,6 @@ import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class ShareLogFragment : Fragment() {
|
||||
|
||||
@@ -91,7 +89,7 @@ class ShareLogFragment : Fragment() {
|
||||
val uri = IOUtils.getUriFromFile(activity, BuildConfig.APPLICATION_ID, files?.get(0))
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.data = uri
|
||||
activity!!.startActivityForResult(intent, LibUIUtils.PICKFILE_REQUEST_CODE)
|
||||
requireActivity().startActivityForResult(intent, LibUIUtils.PICKFILE_REQUEST_CODE)
|
||||
// Dismiss the dialog - it will be re-created in the callback to GpsTestActivity
|
||||
listener.onFileBrowse()
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class UploadDeviceInfoFragment : Fragment() {
|
||||
uploadNoLocationTextView.visibility = View.GONE
|
||||
|
||||
if (Geocoder.isPresent()) {
|
||||
val geocoder = Geocoder(context!!)
|
||||
val geocoder = Geocoder(requireContext())
|
||||
var addresses: List<Address>? = emptyList()
|
||||
try {
|
||||
addresses = geocoder.getFromLocation(location.latitude, location.longitude, 1)
|
||||
|
||||
@@ -44,23 +44,23 @@ import com.android.gpstest.Application
|
||||
import com.android.gpstest.Application.Companion.app
|
||||
import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.R
|
||||
import com.android.gpstest.library.data.FixState
|
||||
import com.android.gpstest.library.data.LocationRepository
|
||||
import com.android.gpstest.databinding.GpsSkyBinding
|
||||
import com.android.gpstest.databinding.GpsSkyLegendCardBinding
|
||||
import com.android.gpstest.databinding.GpsSkySignalMeterBinding
|
||||
import com.android.gpstest.library.data.FixState
|
||||
import com.android.gpstest.library.data.LocationRepository
|
||||
import com.android.gpstest.library.model.SatelliteMetadata
|
||||
import com.android.gpstest.library.model.SatelliteStatus
|
||||
import com.android.gpstest.library.ui.SignalInfoViewModel
|
||||
import com.android.gpstest.ui.status.Filter
|
||||
import com.android.gpstest.ui.theme.AppTheme
|
||||
import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.android.gpstest.library.util.MathUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtil
|
||||
import com.android.gpstest.library.util.PreferenceUtil.darkTheme
|
||||
import com.android.gpstest.library.util.PreferenceUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtils.clearGnssFilter
|
||||
import com.android.gpstest.library.util.PreferenceUtils.gnssFilter
|
||||
import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.android.gpstest.ui.status.Filter
|
||||
import com.android.gpstest.ui.theme.AppTheme
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
@@ -314,7 +314,9 @@ class SkyFragment : Fragment() {
|
||||
legend.skyLegendShapeLine15a,
|
||||
legend.skyLegendShapeLine15b,
|
||||
legend.skyLegendShapeLine16a,
|
||||
legend.skyLegendShapeLine16b
|
||||
legend.skyLegendShapeLine16b,
|
||||
legend.skyLegendShapeLine17a,
|
||||
legend.skyLegendShapeLine17b
|
||||
)
|
||||
|
||||
// Shape Legend shapes
|
||||
@@ -331,7 +333,8 @@ class SkyFragment : Fragment() {
|
||||
legend.skyLegendDiamond4,
|
||||
legend.skyLegendDiamond5,
|
||||
legend.skyLegendDiamond6,
|
||||
legend.skyLegendDiamond7
|
||||
legend.skyLegendDiamond7,
|
||||
legend.skyLegendDiamond8
|
||||
)
|
||||
}
|
||||
|
||||
@@ -584,4 +587,4 @@ class SkyFragment : Fragment() {
|
||||
companion object {
|
||||
const val TAG = "GpsSkyFragment"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,15 +23,36 @@ import android.text.TextUtils
|
||||
import android.text.format.DateFormat
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.material.AlertDialog
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -56,11 +77,10 @@ import com.android.gpstest.library.data.FixState
|
||||
import com.android.gpstest.library.model.CoordinateType
|
||||
import com.android.gpstest.library.model.DilutionOfPrecision
|
||||
import com.android.gpstest.library.model.SatelliteMetadata
|
||||
import com.android.gpstest.library.util.*
|
||||
import com.android.gpstest.library.util.DateTimeUtils
|
||||
import com.android.gpstest.library.util.FormatUtils.formatAccuracy
|
||||
import com.android.gpstest.library.util.FormatUtils.formatAltitude
|
||||
import com.android.gpstest.library.util.FormatUtils.formatAltitudeMsl
|
||||
import com.android.gpstest.ui.components.LinkifyText
|
||||
import com.android.gpstest.library.util.FormatUtils.formatBearing
|
||||
import com.android.gpstest.library.util.FormatUtils.formatBearingAccuracy
|
||||
import com.android.gpstest.library.util.FormatUtils.formatDoP
|
||||
@@ -69,10 +89,14 @@ import com.android.gpstest.library.util.FormatUtils.formatLatOrLon
|
||||
import com.android.gpstest.library.util.FormatUtils.formatNumSats
|
||||
import com.android.gpstest.library.util.FormatUtils.formatSpeed
|
||||
import com.android.gpstest.library.util.FormatUtils.formatSpeedAccuracy
|
||||
import com.android.gpstest.library.util.IOUtils
|
||||
import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtil.coordinateFormat
|
||||
import com.android.gpstest.library.util.PreferenceUtil.shareIncludeAltitude
|
||||
import com.android.gpstest.library.util.PreferenceUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtils.gnssFilter
|
||||
import com.android.gpstest.library.util.SatelliteUtil.isVerticalAccuracySupported
|
||||
import com.android.gpstest.ui.components.LinkifyText
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
@Preview
|
||||
|
||||
@@ -17,7 +17,12 @@
|
||||
package com.android.gpstest.ui.status
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.fragment.app.Fragment
|
||||
@@ -26,8 +31,8 @@ import com.android.gpstest.Application.Companion.app
|
||||
import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.R
|
||||
import com.android.gpstest.library.ui.SignalInfoViewModel
|
||||
import com.android.gpstest.ui.theme.AppTheme
|
||||
import com.android.gpstest.library.util.PreferenceUtil.darkTheme
|
||||
import com.android.gpstest.ui.theme.AppTheme
|
||||
import com.android.gpstest.util.UIUtils.showSortByDialog
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
||||
|
||||
@@ -18,8 +18,23 @@ package com.android.gpstest.ui.status
|
||||
import android.location.Location
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
@@ -45,7 +60,11 @@ import com.android.gpstest.Application.Companion.app
|
||||
import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.R
|
||||
import com.android.gpstest.library.data.FixState
|
||||
import com.android.gpstest.library.model.*
|
||||
import com.android.gpstest.library.model.DilutionOfPrecision
|
||||
import com.android.gpstest.library.model.GnssType
|
||||
import com.android.gpstest.library.model.SatelliteMetadata
|
||||
import com.android.gpstest.library.model.SatelliteStatus
|
||||
import com.android.gpstest.library.model.SbasType
|
||||
import com.android.gpstest.library.ui.SignalInfoViewModel
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils
|
||||
import com.android.gpstest.library.util.MathUtils
|
||||
|
||||
@@ -17,10 +17,8 @@ package com.android.gpstest.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import com.android.gpstest.R
|
||||
import android.location.Location
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
@@ -34,13 +32,14 @@ import androidx.fragment.app.FragmentActivity
|
||||
import com.android.gpstest.Application
|
||||
import com.android.gpstest.Application.Companion.app
|
||||
import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.R
|
||||
import com.android.gpstest.io.CsvFileLogger
|
||||
import com.android.gpstest.io.JsonFileLogger
|
||||
import com.android.gpstest.library.model.GnssType
|
||||
import com.android.gpstest.library.util.IOUtils
|
||||
import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.android.gpstest.library.util.LocationUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtils
|
||||
import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.android.gpstest.ui.GnssFilterDialog
|
||||
import com.android.gpstest.ui.HelpActivity
|
||||
import com.android.gpstest.ui.share.ShareDialogFragment
|
||||
@@ -49,7 +48,6 @@ import com.android.gpstest.ui.share.ShareDialogFragment.Companion.KEY_LOCATION
|
||||
import com.android.gpstest.ui.share.ShareDialogFragment.Companion.KEY_LOGGING_ENABLED
|
||||
import com.android.gpstest.ui.share.ShareDialogFragment.Companion.KEY_LOG_FILES
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Utilities for processing user inteface elements
|
||||
@@ -258,7 +256,7 @@ internal object UIUtils {
|
||||
activity
|
||||
)
|
||||
builder.setTitle(R.string.menu_option_sort_by)
|
||||
val currentSatOrder = PreferenceUtils.getSatSortOrderFromPreferences(app, Application.prefs)
|
||||
val currentSatOrder = PreferenceUtils.getSatSortOrderFromPreferences(app, prefs)
|
||||
builder.setSingleChoiceItems(
|
||||
R.array.sort_sats, currentSatOrder
|
||||
) { dialog: DialogInterface, index: Int ->
|
||||
|
||||
@@ -26,10 +26,10 @@ import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import com.android.gpstest.R;
|
||||
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
import com.android.gpstest.R;
|
||||
|
||||
/**
|
||||
* A layout that draws something in the insets passed to {@link #fitSystemWindows(android.graphics.Rect)},
|
||||
* i.e. the area above UI chrome
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_margin="5dp"
|
||||
app:srcCompat="@drawable/square"
|
||||
android:contentDescription="@string/square"/>/>
|
||||
android:contentDescription="@string/square"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/sky_legend_shape_line2a"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="24dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingEnd="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_permission_instructions"
|
||||
style="?android:attr/textAppearance"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="14dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:text="@string/notification_permission_required_dialog_text"
|
||||
android:textSize="16sp"
|
||||
android:autoLink="web"
|
||||
android:linksClickable="true" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -51,6 +51,11 @@
|
||||
<PreferenceCategory
|
||||
android:title="@string/pref_gps_category_title"
|
||||
android:key="@string/pref_key_gps_category">
|
||||
<CheckBoxPreference
|
||||
android:key="@string/pref_key_show_notification"
|
||||
android:title="@string/pref_gnss_show_notification_title"
|
||||
android:summary="@string/pref_gnss_show_notification_summary"
|
||||
android:defaultValue="false" />
|
||||
<CheckBoxPreference
|
||||
android:key="@string/pref_key_gnss_background"
|
||||
android:title="@string/pref_gnss_background_title"
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package com.android.gpstest.util;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
|
||||
import com.android.gpstest.library.model.DilutionOfPrecision;
|
||||
import com.android.gpstest.library.util.NmeaUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
|
||||
public class NmeaUtilsTest {
|
||||
/**
|
||||
* Test getting altitude above mean sea level (geoid) from NMEA sentences
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# <img src="/icons/ic_launcher-playstore.png" width="50"/> GPSTest
|
||||
[](https://github.com/barbeau/gpstest/actions/workflows/android.yml)
|
||||
[](https://github.com/barbeau/gpstest/issues)
|
||||
[](https://www.buymeacoffee.com/barbeau)
|
||||
[](https://twitter.com/sjbarbeau)
|
||||
[](/LICENSE)
|
||||
|
||||
@@ -68,15 +67,9 @@ Questions? Check out the [FAQ](FAQ.md), the [Slack group](https://gpstest-andro
|
||||
|
||||
- Building the project: You can open and build this project using [Android Studio](https://developer.android.com/studio). For more details, see the [Build documentation](BUILD.MD).
|
||||
|
||||
## Donate
|
||||
|
||||
GPSTest is free and open-source, and I work on it on my lunch breaks as a side project! If you'd like to support GPSTest, please consider [buying me a coffee](https://www.buymeacoffee.com/barbeau).
|
||||
|
||||
[](https://www.buymeacoffee.com/barbeau)
|
||||
|
||||
## Trusted by industry experts
|
||||
|
||||
Notable appearances of GPSTest:
|
||||
|
||||
* Xiaomi - [*Xiaomi Redmi Note 9 Pro Max launch*](https://youtu.be/Y_5cfCZBOV4?t=3035), March 12, 2020.
|
||||
* European Union Global Navigation Satellite Systems Agency (GSA) - [*Test your Android device’s satellite navigation performance*](https://www.gsa.europa.eu/newsroom/news/test-your-android-device-s-satellite-navigation-performance), August 21, 2018.
|
||||
* European Union Global Navigation Satellite Systems Agency (GSA) - [*Test your Android device’s satellite navigation performance*](https://www.euspa.europa.eu/newsroom-events/news-archive/test-your-android-devices-satellite-navigation-performance), August 21, 2018.
|
||||
|
||||
@@ -4,17 +4,18 @@ buildscript {
|
||||
compose_version = '1.2.0-alpha05'
|
||||
wear_compose_version = '1.0.2'
|
||||
}
|
||||
ext.kotlin_version = '1.8.0'
|
||||
ext.hilt_version = '2.45'
|
||||
ext.kotlin_version = '2.1.0'
|
||||
ext.hilt_version = '2.56.2'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.3.1'
|
||||
classpath 'com.android.tools.build:gradle:8.11.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
// Hilt for dependency injection
|
||||
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
|
||||
classpath 'org.jetbrains.kotlin:compose-compiler-gradle-plugin:2.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
fastlane/metadata/android/en-US/changelogs/24098.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/24098.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
• Notification permissions - On fresh installs the GNSS status notification now needs to be enabled in Settings due to changes in how Android handles permissions.
|
||||
• Add support for BDS B2b and IRNSS L1 - Thanks Narugakuruga!
|
||||
• Bug fixes - see http://bit.ly/gpstest-releases
|
||||
@@ -1,23 +1,25 @@
|
||||
No ads, and no trackers - GPSTest displays real-time information for GNSS and SBAS satellites in view of your device. A vital open-source testing tool for platform engineers, developers, and power users, GPSTest can also assist in understanding why your GPS/GNSS isn't working.
|
||||
|
||||
Supports dual-frequency* GNSS for:
|
||||
• GPS (USA Navstar) (L1, L2, L3, L4, L5)
|
||||
• Galileo (European Union) (E1, E5, E5a, E5b, E6)
|
||||
• GLONASS (Russia) (L1, L2, L3, L5)
|
||||
• QZSS (Japan) (L1, L2, L5, L6)
|
||||
• BeiDou/COMPASS (China) (B1, B1-2, B2, B2a, B3)
|
||||
• IRNSS/NavIC (India) (L5, S)
|
||||
• Various satellite-based augmentation systems SBAS (e.g., GAGAN, Anik F1, Galaxy 15, Inmarsat 3-F2, Inmarsat 4-F3, SES-5) (L1, L5)
|
||||
|
||||
* GPS (USA Navstar) (L1, L2, L3, L4, L5)
|
||||
* Galileo (European Union) (E1, E5, E5a, E5b, E6)
|
||||
* GLONASS (Russia) (L1, L2, L3, L5)
|
||||
* QZSS (Japan) (L1, L2, L5, L6)
|
||||
* BeiDou/COMPASS (China) (B1I, B2a, B2b, B3I)
|
||||
* IRNSS/NavIC (India) (L1, L5, S)
|
||||
* Various satellite-based augmentation systems SBAS (e.g., GAGAN, Anik F1, Galaxy 15, Inmarsat 3-F2, Inmarsat 4-F3, SES-5) (L1, L5)
|
||||
|
||||
*Dual-frequency GNSS requires device hardware support and Android 8.0 Oreo or higher. More at https://medium.com/@sjbarbeau/dual-frequency-gnss-on-android-devices-152b8826e1c.
|
||||
|
||||
The "Accuracy" feature lets you measure the error in your device's position against your *actual* location (entered by you). Other apps show you the *estimated* accuracy, which is generated by your device. GPSTest lets you to compare this estimated accuracy to *actual* accuracy!
|
||||
|
||||
Menu options:
|
||||
• Inject Time Data - Injects Time assistance data for GPS into the platform, using information from a Network Time Protocol (NTP) server
|
||||
• Inject PSDS Data - Injects Predicted Satellite Data Service (PSDS) assistance data for GNSS into the platform, using information from a PSDS server. Note that some devices don't use PSDS for assistance data - if this is your device, you'll see a message saying "Platform does not support injecting PSDS data". PSDS is the generic term for products like [XTRA assistance data](http://goo.gl/3RjWX).
|
||||
• Clear Assist Data - Clears all assistance data used for GNSS, including NTP and XTRA data (Note: if you select this option to fix broken GNSS on your device, for GPS to work again you may need to ‘Inject Time’ and ‘Inject PSDS’ data. You may also see a large delay until your device acquires a fix again, so please use this feature with caution.)
|
||||
• Settings - Switch between light and dark themes, change map tile type, auto-start GPS on startup, minimum time and distance between GPS updates, keep screen on.
|
||||
|
||||
* Inject Time Data - Injects Time assistance data for GPS into the platform, using information from a Network Time Protocol (NTP) server
|
||||
* Inject PSDS Data - Injects Predicted Satellite Data Service (PSDS) assistance data for GNSS into the platform, using information from a PSDS server. Note that some devices don't use PSDS for assistance data - if this is your device, you'll see a message saying "Platform does not support injecting PSDS data". PSDS is the generic term for products like [XTRA assistance data](https://www.qualcomm.com/news/releases/2007/02/qualcomm-introduces-gpsonextra-assistance-expand-capabilities-standalone).
|
||||
* Clear Assist Data - Clears all assistance data used for GNSS, including NTP and XTRA data (Note: if you select this option to fix broken GNSS on your device, for GPS to work again you may need to ‘Inject Time’ and ‘Inject PSDS’ data. You may also see a large delay until your device acquires a fix again, so please use this feature with caution.)
|
||||
* Settings - Switch between light and dark themes, change map tile type, auto-start GPS on startup, minimum time and distance between GPS updates, keep screen on.
|
||||
|
||||
Beta versions:
|
||||
https://play.google.com/apps/testing/com.android.gpstest
|
||||
@@ -35,4 +37,4 @@ Nostalgic for old releases? Download old versions here:
|
||||
https://github.com/barbeau/gpstest/releases
|
||||
|
||||
Also available on Google Play:
|
||||
https://play.google.com/store/apps/details?id=com.android.gpstest
|
||||
https://play.google.com/store/apps/details?id=com.android.gpstest
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.parallel=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.caching=false
|
||||
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC
|
||||
org.gradle.caching=true
|
||||
org.gradle.jvmargs=-Xmx3g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:+UseParallelGC
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
android.useAndroidX=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,7 @@
|
||||
#Tue Dec 01 16:08:35 EST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
||||
|
||||
312
gradlew
vendored
312
gradlew
vendored
@@ -1,78 +1,130 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# 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
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m"'
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
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"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -81,92 +133,120 @@ 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.
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "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" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
78
gradlew.bat
vendored
78
gradlew.bat
vendored
@@ -1,4 +1,22 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -9,25 +27,29 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@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="-Xmx64m"
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@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
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
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.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -35,48 +57,36 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
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.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_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=%*
|
||||
|
||||
: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%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 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
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -18,12 +18,13 @@ android {
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
||||
}
|
||||
}
|
||||
lint {
|
||||
disable "JvmStaticProvidesInObjectDetector", "FieldSiteTargetOnQualifierAnnotation", "ModuleCompanionObjects", "ModuleCompanionObjectsNotInModuleParent"
|
||||
|
||||
lintOptions {
|
||||
disable "JvmStaticProvidesInObjectDetector", "FieldSiteTargetOnQualifierAnnotation", "ModuleCompanionObjects", "ModuleCompanionObjectsNotInModuleParent", 'StringFormatInvalid', 'MissingTranslation', 'ExtraTranslation', 'ExpiredTargetSdkVersion'
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
@@ -36,11 +37,11 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = JavaVersion.VERSION_17
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.android.library
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest>
|
||||
|
||||
</manifest>
|
||||
@@ -36,7 +36,6 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import java.util.*
|
||||
|
||||
private const val TAG = "SharedAntennaManager"
|
||||
|
||||
|
||||
@@ -36,7 +36,12 @@ import com.android.gpstest.library.util.hasPermission
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
|
||||
private const val TAG = "SharedGnssMeasurementManager"
|
||||
|
||||
|
||||
@@ -33,7 +33,12 @@ import com.android.gpstest.library.util.hasPermission
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
private const val TAG = "SharedGnssStatusManager"
|
||||
|
||||
@@ -29,7 +29,12 @@ import com.android.gpstest.library.util.hasPermission
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
|
||||
private const val TAG = "SharedLocationManager"
|
||||
|
||||
|
||||
@@ -19,7 +19,11 @@ import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.hardware.*
|
||||
import android.hardware.GeomagneticField
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.location.LocationManager
|
||||
import android.util.Log
|
||||
@@ -138,16 +142,18 @@ class SharedSensorManager constructor(
|
||||
)
|
||||
} else if (SatelliteUtils.isOrientationSensorSupported(context)) {
|
||||
// Use the legacy orientation sensors
|
||||
val sensor: Sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION)
|
||||
sensorManager.registerListener(
|
||||
callback,
|
||||
sensor,
|
||||
ROT_VECTOR_SENSOR_DELAY_MICROS
|
||||
val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION)
|
||||
if (sensor != null) {
|
||||
sensorManager.registerListener(
|
||||
callback,
|
||||
sensor,
|
||||
ROT_VECTOR_SENSOR_DELAY_MICROS
|
||||
)
|
||||
} else {
|
||||
// No sensors to observe
|
||||
Log.e(TAG, "Device doesn't support sensor TYPE_ROTATION_VECTOR or TYPE_ORIENTATION")
|
||||
Log.e(TAG, "Device doesn't support sensor TYPE_ROTATION_VECTOR or TYPE_ORIENTATION")
|
||||
close()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Exception in sensor flow: $e")
|
||||
|
||||
@@ -3,7 +3,13 @@ package com.android.gpstest.library.di
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.preference.PreferenceManager
|
||||
import com.android.gpstest.library.data.*
|
||||
import com.android.gpstest.library.data.SharedAntennaManager
|
||||
import com.android.gpstest.library.data.SharedGnssMeasurementManager
|
||||
import com.android.gpstest.library.data.SharedGnssStatusManager
|
||||
import com.android.gpstest.library.data.SharedLocationManager
|
||||
import com.android.gpstest.library.data.SharedNavMessageManager
|
||||
import com.android.gpstest.library.data.SharedNmeaManager
|
||||
import com.android.gpstest.library.data.SharedSensorManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
||||
@@ -28,7 +28,13 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.android.gpstest.library.data.FirstFixState
|
||||
import com.android.gpstest.library.data.FixState
|
||||
import com.android.gpstest.library.data.LocationRepository
|
||||
import com.android.gpstest.library.model.*
|
||||
import com.android.gpstest.library.model.DilutionOfPrecision
|
||||
import com.android.gpstest.library.model.GnssType
|
||||
import com.android.gpstest.library.model.Satellite
|
||||
import com.android.gpstest.library.model.SatelliteGroup
|
||||
import com.android.gpstest.library.model.SatelliteMetadata
|
||||
import com.android.gpstest.library.model.SatelliteStatus
|
||||
import com.android.gpstest.library.model.SbasType
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils.getCarrierFrequencyLabel
|
||||
import com.android.gpstest.library.util.FormatUtils.formatTtff
|
||||
import com.android.gpstest.library.util.NmeaUtils
|
||||
|
||||
@@ -126,17 +126,15 @@ public class CarrierFreqUtils {
|
||||
*/
|
||||
public static String getBeidoucCf(double carrierFrequencyMhz) {
|
||||
if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1561.098, CF_TOLERANCE_MHZ)) {
|
||||
return "B1";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1589.742, CF_TOLERANCE_MHZ)) {
|
||||
return "B1-2";
|
||||
return "B1I";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1575.42, CF_TOLERANCE_MHZ)) {
|
||||
return "B1C";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1207.14, CF_TOLERANCE_MHZ)) {
|
||||
return "B2";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1176.45, CF_TOLERANCE_MHZ)) {
|
||||
return "B2a";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1207.14, CF_TOLERANCE_MHZ)) {
|
||||
return "B2b";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1268.52, CF_TOLERANCE_MHZ)) {
|
||||
return "B3";
|
||||
return "B3I";
|
||||
} else {
|
||||
return CF_UNKNOWN;
|
||||
}
|
||||
@@ -188,7 +186,9 @@ public class CarrierFreqUtils {
|
||||
* @return carrier frequency label
|
||||
*/
|
||||
public static String getIrnssCf(double carrierFrequencyMhz) {
|
||||
if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1176.45, CF_TOLERANCE_MHZ)) {
|
||||
if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1575.42, CF_TOLERANCE_MHZ)) {
|
||||
return "L1";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 1176.45, CF_TOLERANCE_MHZ)) {
|
||||
return "L5";
|
||||
} else if (MathUtils.fuzzyEquals(carrierFrequencyMhz, 2492.028, CF_TOLERANCE_MHZ)) {
|
||||
return "S";
|
||||
@@ -289,6 +289,6 @@ public class CarrierFreqUtils {
|
||||
* * frequency
|
||||
*/
|
||||
public static boolean isPrimaryCarrier(String label) {
|
||||
return label.equals("L1") || label.equals("E1") || label.equals("L1-C") || label.equals("B1") || label.equals("B1C");
|
||||
return label.equals("L1") || label.equals("E1") || label.equals("L1-C") || label.equals("B1I") || label.equals("B1C");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,12 @@ import android.location.Location
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.android.gpstest.library.R
|
||||
import com.android.gpstest.library.model.*
|
||||
import com.android.gpstest.library.model.CoordinateType
|
||||
import com.android.gpstest.library.model.DilutionOfPrecision
|
||||
import com.android.gpstest.library.model.Orientation
|
||||
import com.android.gpstest.library.model.SatelliteGroup
|
||||
import com.android.gpstest.library.model.SatelliteMetadata
|
||||
import com.android.gpstest.library.model.SatelliteStatus
|
||||
import com.android.gpstest.library.util.SatelliteUtil.isBearingAccuracySupported
|
||||
import com.android.gpstest.library.util.SatelliteUtil.isSpeedAccuracySupported
|
||||
import com.android.gpstest.library.util.SatelliteUtil.isVerticalAccuracySupported
|
||||
|
||||
@@ -52,7 +52,7 @@ import com.android.gpstest.library.ui.SignalInfoViewModel
|
||||
import com.google.android.material.chip.Chip
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import java.util.*
|
||||
import java.util.Collections
|
||||
|
||||
/**
|
||||
* Utilities for processing user interface elements
|
||||
|
||||
@@ -16,19 +16,22 @@
|
||||
package com.android.gpstest.library.util;
|
||||
|
||||
import android.Manifest;
|
||||
import android.Manifest.permission;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
public class PermissionUtils {
|
||||
public static final int LOCATION_PERMISSION_REQUEST = 1;
|
||||
public static final int NOTIFICATION_PERMISSION_REQUEST = 1;
|
||||
|
||||
public static final String[] REQUIRED_PERMISSIONS = {
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -45,4 +48,19 @@ public class PermissionUtils {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the permission string for notification permission */
|
||||
@RequiresApi(api = VERSION_CODES.TIRAMISU)
|
||||
public static String getNotificationPermission() {
|
||||
return Manifest.permission.POST_NOTIFICATIONS;
|
||||
}
|
||||
|
||||
/** Returns true if the context has been granted notification permissions, false if it has not. */
|
||||
public static boolean hasGrantedNotificationPermissions(Context context) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) {
|
||||
return ContextCompat.checkSelfPermission(context, getNotificationPermission())
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import com.android.gpstest.library.R;
|
||||
import com.android.gpstest.library.model.GnssType;
|
||||
|
||||
|
||||
@@ -19,8 +19,16 @@ import android.annotation.SuppressLint
|
||||
import android.location.GnssStatus
|
||||
import android.location.Location
|
||||
import android.os.Build
|
||||
import com.android.gpstest.library.model.*
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils.*
|
||||
import com.android.gpstest.library.model.GnssType
|
||||
import com.android.gpstest.library.model.Satellite
|
||||
import com.android.gpstest.library.model.SatelliteGroup
|
||||
import com.android.gpstest.library.model.SatelliteMetadata
|
||||
import com.android.gpstest.library.model.SatelliteStatus
|
||||
import com.android.gpstest.library.model.SbasType
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils.CF_UNKNOWN
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils.CF_UNSUPPORTED
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils.getCarrierFrequencyLabel
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils.isPrimaryCarrier
|
||||
import com.android.gpstest.library.util.SatelliteUtils.createGnssSatelliteKey
|
||||
|
||||
object SatelliteUtil {
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
<string name="pref_key_gps_min_time">gps_min_time</string>
|
||||
<string name="pref_key_gps_min_distance">gps_min_distance</string>
|
||||
<string name="pref_key_gnss_background">gnss_background</string>
|
||||
<string name="pref_key_show_notification">show_notification</string>
|
||||
|
||||
<string name="pref_key_display_category">display_category</string>
|
||||
<string name="pref_key_keep_screen_on">keep_screen_on</string>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Fragments -->
|
||||
<string name="gps_status_title">Status</string>
|
||||
<string name="gps_map_title">Map</string>
|
||||
@@ -149,7 +149,7 @@
|
||||
<string name="sdcm_content_description">SDCM</string>
|
||||
<string name="snas_content_description">SNAS</string>
|
||||
<string name="saccsa_content_description">SACCSA</string>
|
||||
<string name="southpan_content_description">SouthPAN</string>
|
||||
<string name="southpan_content_description">SouthPAN</string>
|
||||
|
||||
<!-- Map view -->
|
||||
<string name="ground_truth_latitude">Your latitude</string>
|
||||
@@ -246,6 +246,26 @@
|
||||
<string name="ok">OK</string>
|
||||
<string name="exit">EXIT</string>
|
||||
|
||||
<string name="notification_permission_required_dialog_title" tools:ignore="MissingTranslation">
|
||||
Notification permission required
|
||||
</string>
|
||||
|
||||
<string name="notification_permission_required_dialog_text" tools:ignore="MissingTranslation">
|
||||
You must grant notification permissions before enabling this setting. Tap \"Ok\" to grant permissions.
|
||||
</string>
|
||||
|
||||
<string name="can_not_disable_setting_dialog_text" tools:ignore="MissingTranslation">
|
||||
You can\'t disable notifications while background execution or file logging is enabled. Please disable these settings first.
|
||||
</string>
|
||||
|
||||
<string name="need_to_restart_application_dialog_title" tools:ignore="MissingTranslation">
|
||||
App restart required
|
||||
</string>
|
||||
|
||||
<string name="need_to_restart_application_dialog_text" tools:ignore="MissingTranslation">
|
||||
To revoke notification permissions the application needs to be restarted. Tap \"Ok\" to restart.
|
||||
</string>
|
||||
|
||||
<!-- Send feedback -->
|
||||
<string name="feedback_subject">GPSTest: Feedback</string>
|
||||
<string name="feedback_body">Complaints, kudos, or bug reports are welcome!\n\n\n</string>
|
||||
@@ -255,18 +275,10 @@
|
||||
<!-- What's New -->
|
||||
<string name="main_help_whatsnew_title">What\'s New?</string>
|
||||
<string name="main_help_whatsnew">•\u0020
|
||||
<b>Background execution</b>
|
||||
- You can now log on your device while you do something else!\n•\u0020
|
||||
<b>GNSS status notification</b>
|
||||
- Shows the number of signals & satellites in view and in use in a convenient notification.\n•\u0020
|
||||
<b>Filter the Sky</b>
|
||||
- The filter feature now works on the Status AND Sky screens!\n•\u0020
|
||||
<b>Themed icon support (Android 13 and up)</b>
|
||||
- No more disruptions to your otherwise color-perfect home screen :).\n•\u0020
|
||||
<b>Log files available in \"Downloads/GPSTest\" directory (Android 11 and up)</b>
|
||||
- To comply with new Android permission requirements.\n•\u0020
|
||||
<b>Support for SouthPAN SBAS</b>
|
||||
- Thanks Dave Collett!\n•\u0020
|
||||
<b>Notification permissions</b>
|
||||
- On fresh installs the GNSS status notification now needs to be enabled in Settings due to changes in how Android handles permissions.\n•\u0020
|
||||
<b>Add support for BDS B2b and IRNSS L1</b>
|
||||
- Thanks Narugakuruga!\n•\u0020
|
||||
<b>Bug fixes</b>
|
||||
- See https://bit.ly/gpstest-releases
|
||||
</string>
|
||||
@@ -297,6 +309,9 @@
|
||||
<string name="pref_auto_start_gps_title">Auto-Start GNSS</string>
|
||||
<string name="pref_auto_start_gps_summary">Start GNSS when the app starts</string>
|
||||
|
||||
<string name="pref_gnss_show_notification_title">Show a notification</string>
|
||||
<string name="pref_gnss_show_notification_summary">If checked, the app will show a notification with real-time GNSS information. This setting must be enabled to run in the background or log data. When disabling this setting you must kill and restart the app for it to take effect. This setting can only be changed on Android 13 and up.</string>
|
||||
|
||||
<string name="pref_gnss_background_title">Run GNSS in background</string>
|
||||
<string name="pref_gnss_background_summary">If checked, when you leave the app a notification will keep GNSS running in the background until you stop it from that notification. This setting is automatically enabled when you enable logging data to files to allow logging in the background.</string>
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.android.library
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
|
||||
@@ -3,6 +3,7 @@ plugins {
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'kotlin-kapt'
|
||||
id 'dagger.hilt.android.plugin'
|
||||
id 'org.jetbrains.kotlin.plugin.compose'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -33,11 +34,11 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = JavaVersion.VERSION_17
|
||||
freeCompilerArgs += [
|
||||
"-opt-in=kotlin.RequiresOptIn",
|
||||
"-Xjvm-default=all"]
|
||||
|
||||
@@ -37,4 +37,4 @@
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
||||
@@ -13,12 +13,15 @@ import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -34,13 +37,19 @@ import androidx.core.app.ActivityCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.flowWithLifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.wear.compose.material.*
|
||||
import androidx.wear.compose.material.Text
|
||||
import com.android.gpstest.Application.Companion.prefs
|
||||
import com.android.gpstest.library.data.FixState
|
||||
import com.android.gpstest.library.data.LocationRepository
|
||||
import com.android.gpstest.library.model.*
|
||||
import com.android.gpstest.library.model.GnssType
|
||||
import com.android.gpstest.library.model.SatelliteStatus
|
||||
import com.android.gpstest.library.model.SbasType
|
||||
import com.android.gpstest.library.ui.SignalInfoViewModel
|
||||
import com.android.gpstest.library.util.*
|
||||
import com.android.gpstest.library.util.CarrierFreqUtils
|
||||
import com.android.gpstest.library.util.LibUIUtils
|
||||
import com.android.gpstest.library.util.MathUtils
|
||||
import com.android.gpstest.library.util.PermissionUtils
|
||||
import com.android.gpstest.library.util.PreferenceUtil
|
||||
import com.android.gpstest.library.util.PreferenceUtils
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.Job
|
||||
|
||||
@@ -23,7 +23,14 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.rotary.onRotaryScrollEvent
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.wear.compose.material.*
|
||||
import androidx.wear.compose.material.AutoCenteringParams
|
||||
import androidx.wear.compose.material.PositionIndicator
|
||||
import androidx.wear.compose.material.Scaffold
|
||||
import androidx.wear.compose.material.ScalingLazyColumn
|
||||
import androidx.wear.compose.material.Text
|
||||
import androidx.wear.compose.material.TimeSource
|
||||
import androidx.wear.compose.material.TimeText
|
||||
import androidx.wear.compose.material.rememberScalingLazyListState
|
||||
import com.android.gpstest.Application
|
||||
import com.android.gpstest.library.data.FixState
|
||||
import com.android.gpstest.library.model.CoordinateType
|
||||
|
||||
Reference in New Issue
Block a user