Skip to content

Commit

Permalink
Fix #369 - Highlight wrong GNSS times on Status (#376)
Browse files Browse the repository at this point in the history
* Current threshold is more than 5 days different than system clock
  • Loading branch information
barbeau authored Feb 20, 2020
1 parent c22d0b4 commit d214011
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 10 deletions.
4 changes: 4 additions & 0 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ Then tap on "Send feedback", and GPSTest it will capture success/failure for all

No. See our [Privacy Policy](https://github.com/barbeau/gpstest/wiki/Privacy-Policy) for more details.

## Why is my GPS time wrong?

As of April 6, 2019, some older devices have been impacted by the [GPS Week Number Rollover](https://www.cisa.gov/gps-week-number-roll-over), which can result in unpredictable behavior. Typically, the time computed by GPS will be wrong. You will need to contact your device manufacturer or cellular carrier to determine if you device can be updated to fix this issue. For example, here is [Verizon's GPS Week Rollover help page](https://www.verizonwireless.com/legal/notices/global-positioning-system/).

## I'm getting a weird value for Time-to-First-Fix. What's up?

On Android 4.1 and below, your system clock must be accurate to calculate an accurate Time-To-First-Fix (TTFF) value
Expand Down
38 changes: 36 additions & 2 deletions GPSTest/src/main/java/com/android/gpstest/GpsStatusFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.cardview.widget.CardView;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
Expand All @@ -58,6 +59,7 @@
import com.android.gpstest.model.SatelliteMetadata;
import com.android.gpstest.model.SatelliteStatus;
import com.android.gpstest.util.CarrierFreqUtils;
import com.android.gpstest.util.DateTimeUtils;
import com.android.gpstest.util.IOUtils;
import com.android.gpstest.util.MathUtils;
import com.android.gpstest.util.NmeaUtils;
Expand Down Expand Up @@ -95,7 +97,7 @@ public class GpsStatusFragment extends Fragment implements GpsTestListener {
mAltitudeMslView, mHorVertAccuracyLabelView, mHorVertAccuracyView,
mSpeedView, mSpeedAccuracyView, mBearingView, mBearingAccuracyView, mNumSats,
mPdopLabelView, mPdopView, mHvdopLabelView, mHvdopView, mGnssNotAvailableView,
mSbasNotAvailableView;
mSbasNotAvailableView, mFixTimeErrorView;

private CardView mLocationCard;

Expand Down Expand Up @@ -160,6 +162,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,
mLatitudeView = v.findViewById(R.id.latitude);
mLongitudeView = v.findViewById(R.id.longitude);
mFixTimeView = v.findViewById(R.id.fix_time);
mFixTimeErrorView = v.findViewById(R.id.fix_time_error);
mFixTimeErrorView.setOnClickListener(view -> showTimeErrorDialog(mFixTime));
mTTFFView = v.findViewById(R.id.ttff);
mAltitudeView = v.findViewById(R.id.altitude);
mAltitudeMslView = v.findViewById(R.id.altitude_msl);
Expand Down Expand Up @@ -271,8 +275,18 @@ private void setStarted(boolean navigating) {
private void updateFixTime() {
if (mFixTime == 0 || (GpsTestActivity.getInstance() != null && !GpsTestActivity.getInstance().mStarted)) {
mFixTimeView.setText("");
mFixTimeErrorView.setText("");
} else {
mFixTimeView.setText(mDateFormat.format(mFixTime));
if (DateTimeUtils.Companion.isTimeValid(mFixTime)) {
mFixTimeErrorView.setVisibility(View.GONE);
mFixTimeView.setVisibility(View.VISIBLE);
mFixTimeView.setText(mDateFormat.format(mFixTime));
} else {
// Error in fix time
mFixTimeErrorView.setVisibility(View.VISIBLE);
mFixTimeView.setVisibility(View.GONE);
mFixTimeErrorView.setText(mDateFormat.format(mFixTime));
}
}
}

Expand Down Expand Up @@ -739,6 +753,26 @@ private void showSortByDialog() {
dialog.show();
}

private void showTimeErrorDialog(long time) {
java.text.DateFormat format = SimpleDateFormat.getDateTimeInstance(java.text.DateFormat.LONG, java.text.DateFormat.LONG);

TextView textView = (TextView) getLayoutInflater().inflate(R.layout.error_text_dialog, null);
textView.setText(getString(R.string.error_time_message, format.format(time), DateTimeUtils.Companion.getNUM_DAYS_TIME_VALID()));

AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.error_time_title);
builder.setView(textView);
Drawable drawable = getResources().getDrawable(android.R.drawable.ic_dialog_alert);
DrawableCompat.setTint(drawable, getResources().getColor(R.color.colorPrimary));
builder.setIcon(drawable);
builder.setNeutralButton(R.string.main_help_close,
(dialog, which) -> dialog.dismiss()
);
AlertDialog dialog = builder.create();
dialog.setOwnerActivity(getActivity());
dialog.show();
}

/**
* Saves the "sort by" order to preferences
*
Expand Down
50 changes: 50 additions & 0 deletions GPSTest/src/main/java/com/android/gpstest/util/DateTimeUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2020 Sean J. Barbeau
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.android.gpstest.util

import android.os.Build
import androidx.annotation.VisibleForTesting
import java.time.Duration
import java.time.Instant
import java.util.concurrent.TimeUnit

/**
* Utilities for comparing two locations to measure error
*/
class DateTimeUtils {

companion object {
val NUM_DAYS_TIME_VALID = 5
/**
* Returns true if the provided UTC time of the fix, in milliseconds since January 1, 1970,
* is valid, and false if it is not
*/
fun isTimeValid(time: Long): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// If the GPS time is less than five days different than system clock time, consider it valid
Duration.between(Instant.ofEpochMilli(time), Instant.now()).toDays() < NUM_DAYS_TIME_VALID
} else {
isTimeValidLegacy(time)
}
}

@VisibleForTesting
internal fun isTimeValidLegacy(time: Long): Boolean {
return TimeUnit.MILLISECONDS.toDays(Math.abs(System.currentTimeMillis() - time)) < NUM_DAYS_TIME_VALID
}
}
}
22 changes: 22 additions & 0 deletions GPSTest/src/main/res/drawable/error_text_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Outside border -->
<item android:id="@+id/error_background_border">
<shape>
<corners android:radius="9dp" />
<padding
android:top="3dp"
android:left="3dp"
android:bottom="3dp"
android:right="3dp" />
<solid android:color="@color/red" />
</shape>
</item>
<!-- Inside fill -->
<item android:id="@+id/error_background_fill">
<shape>
<corners android:radius="6dp" />
<solid android:color="@color/red" />
</shape>
</item>
</layer-list>
12 changes: 12 additions & 0 deletions GPSTest/src/main/res/layout/error_text_dialog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
style="?android:attr/textAppearance"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="14dp"
android:paddingBottom="6dp"
android:paddingLeft="24dp"
android:paddingRight="10dp"
android:textSize="16sp"
android:autoLink="all"
android:linksClickable="true"></TextView>
5 changes: 5 additions & 0 deletions GPSTest/src/main/res/layout/gps_status.xml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
<TextView
android:id="@+id/fix_time"
style="@style/info_value" />

<TextView
android:id="@+id/fix_time_error"
style="@style/info_value_error"
android:visibility="gone" />
</TableRow>

<TableRow>
Expand Down
2 changes: 2 additions & 0 deletions GPSTest/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@
<string name="gnss_not_available">Global Navigation Satellite System (GNSS) satellites not available</string>
<string name="sbas_not_available">Satellite-based Augmentation System (SBAS) satellites not available</string>
<string name="menu_option_sort_by">Sort by</string>
<string name="error_time_title">Your GNSS time is wrong</string>
<string name="error_time_message">The device GNSS time of:\n\n%1$s\n\n…is more than %2$d days different from your system clock. This can be caused by the GPS week rollover issue - ask your device manufacturer for details. See http://bit.ly/gps-week-rollover for more info.</string>

<!-- Map view -->
<string name="ground_truth_latitude">Your latitude</string>
Expand Down
13 changes: 13 additions & 0 deletions GPSTest/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@
<item name="android:textStyle">normal</item>
</style>

<style name="info_value_error">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:textSize">@dimen/status_text_size</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:paddingTop">3dp</item>
<item name="android:paddingBottom">3dp</item>
<item name="android:paddingLeft">6dp</item>
<item name="android:paddingRight">6dp</item>
<item name="android:background">@drawable/error_text_background</item>
</style>

<!-- GNSS Sky view -->
<style name="sky_legend_label">
<item name="android:layout_height">wrap_content</item>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2020 Sean J. Barbeau
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.gpstest.util

import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Test
import java.time.Instant
import java.util.concurrent.TimeUnit

class DateTimeUtilsTest {

@Test
fun isTimeValid() {
// Valid times within 5 days of now
assertTrue(DateTimeUtils.isTimeValid(Instant.now().toEpochMilli()))
assertTrue(DateTimeUtils.isTimeValid(Instant.now().toEpochMilli() + TimeUnit.DAYS.toMillis(4)))
assertTrue(DateTimeUtils.isTimeValid(Instant.now().toEpochMilli() - TimeUnit.DAYS.toMillis(4)))

// Invalid times more than 5 days from now (past or future)
assertFalse(DateTimeUtils.isTimeValid(Instant.now().toEpochMilli() + TimeUnit.DAYS.toMillis(6)))
assertFalse(DateTimeUtils.isTimeValid(Instant.now().toEpochMilli() - TimeUnit.DAYS.toMillis(6)))
}

@Test
fun isTimeValidLegacy() {
// Valid times within 5 days of now
assertTrue(DateTimeUtils.isTimeValidLegacy(Instant.now().toEpochMilli()))
assertTrue(DateTimeUtils.isTimeValidLegacy(Instant.now().toEpochMilli() + TimeUnit.DAYS.toMillis(4)))
assertTrue(DateTimeUtils.isTimeValidLegacy(Instant.now().toEpochMilli() - TimeUnit.DAYS.toMillis(4)))

// Invalid times more than 5 days from now (past or future)
assertFalse(DateTimeUtils.isTimeValidLegacy(Instant.now().toEpochMilli() + TimeUnit.DAYS.toMillis(6)))
assertFalse(DateTimeUtils.isTimeValidLegacy(Instant.now().toEpochMilli() - TimeUnit.DAYS.toMillis(6)))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.gpstest;

import com.android.gpstest.util.MathUtils;
package com.android.gpstest.util;

import org.junit.Test;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.gpstest;
package com.android.gpstest.util;

import com.android.gpstest.model.DilutionOfPrecision;
import com.android.gpstest.util.NmeaUtils;

import org.junit.Test;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
package com.android.gpstest;

import com.android.gpstest.util.UIUtils;
package com.android.gpstest.util;

import org.junit.Test;

Expand Down

0 comments on commit d214011

Please sign in to comment.