Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE
+
Copyright 2021 Cappuccino Authors
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FFImageLoading
diff --git a/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj b/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj
index 886331bab..a54b75185 100644
--- a/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj
+++ b/Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj
@@ -485,9 +485,6 @@
-
-
-
@@ -536,9 +533,6 @@
-
-
-
diff --git a/Covid19Radar/Covid19Radar.Android/MainActivity.cs b/Covid19Radar/Covid19Radar.Android/MainActivity.cs
index 07b976ac9..c3c6068f1 100644
--- a/Covid19Radar/Covid19Radar.Android/MainActivity.cs
+++ b/Covid19Radar/Covid19Radar.Android/MainActivity.cs
@@ -160,7 +160,7 @@ private void FireExposureNotificationEvent(int requestCode, bool isOk)
ExposureNotificationApiService.REQUEST_EN_START
=> new Action(callback =>
{
- if(isOk)
+ if (isOk)
{
callback.OnEnabled();
}
@@ -170,7 +170,17 @@ private void FireExposureNotificationEvent(int requestCode, bool isOk)
}
}),
ExposureNotificationApiService.REQUEST_GET_TEK_HISTORY
- => new Action(callback => { callback.OnGetTekHistoryAllowed(); }),
+ => new Action(callback =>
+ {
+ if (isOk)
+ {
+ callback.OnGetTekHistoryAllowed();
+ }
+ else
+ {
+ callback.OnGetTekHistoryDecline();
+ }
+ }),
ExposureNotificationApiService.REQUEST_PREAUTHORIZE_KEYS
=> new Action(callback => { callback.OnPreauthorizeAllowed(); }),
_ => new Action(callback => { /* do nothing */ }),
diff --git a/Covid19Radar/Covid19Radar.Android/Resources/drawable-xhdpi/TutorialPage50.png b/Covid19Radar/Covid19Radar.Android/Resources/drawable-xhdpi/TutorialPage50.png
deleted file mode 100644
index be77ad710..000000000
Binary files a/Covid19Radar/Covid19Radar.Android/Resources/drawable-xhdpi/TutorialPage50.png and /dev/null differ
diff --git a/Covid19Radar/Covid19Radar.Android/Resources/drawable-xxhdpi/TutorialPage50.png b/Covid19Radar/Covid19Radar.Android/Resources/drawable-xxhdpi/TutorialPage50.png
deleted file mode 100644
index a3e781529..000000000
Binary files a/Covid19Radar/Covid19Radar.Android/Resources/drawable-xxhdpi/TutorialPage50.png and /dev/null differ
diff --git a/Covid19Radar/Covid19Radar.Android/Resources/values/styles.xml b/Covid19Radar/Covid19Radar.Android/Resources/values/styles.xml
index dfa365212..2c21aa09c 100644
--- a/Covid19Radar/Covid19Radar.Android/Resources/values/styles.xml
+++ b/Covid19Radar/Covid19Radar.Android/Resources/values/styles.xml
@@ -44,5 +44,7 @@
diff --git a/Covid19Radar/Covid19Radar.Android/Services/ExposureDetectionBackgroundService.cs b/Covid19Radar/Covid19Radar.Android/Services/ExposureDetectionBackgroundService.cs
index f4af3db04..cd8197a30 100644
--- a/Covid19Radar/Covid19Radar.Android/Services/ExposureDetectionBackgroundService.cs
+++ b/Covid19Radar/Covid19Radar.Android/Services/ExposureDetectionBackgroundService.cs
@@ -3,7 +3,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
+using System.Collections.Generic;
using System.IO;
+using System.Linq;
using Android.Content;
using Android.Runtime;
using AndroidX.Work;
@@ -83,9 +85,6 @@ private static PeriodicWorkRequest CreatePeriodicWorkRequest()
[Preserve]
public class BackgroundWorker : Worker
{
- private readonly Lazy _exposureNotificationApiService
- = new Lazy(() => ContainerLocator.Current.Resolve());
-
private readonly Lazy _loggerService
= new Lazy(() => ContainerLocator.Current.Resolve());
@@ -99,19 +98,11 @@ public BackgroundWorker(Context context, WorkerParameters workerParameters)
public override Result DoWork()
{
- var exposureNotificationApiService = _exposureNotificationApiService.Value;
var loggerService = _loggerService.Value;
var backgroundService = _backgroundService.Value;
loggerService.StartMethod();
- if (!exposureNotificationApiService.IsEnabledAsync().GetAwaiter().GetResult())
- {
- loggerService.Debug($"EN API is not enabled." +
- $" worker will start after {ExposureDetectionBackgroundService.INTERVAL_IN_MINUTES} minutes later.");
- return Result.InvokeSuccess();
- }
-
try
{
backgroundService.ExposureDetectionAsync().GetAwaiter().GetResult();
diff --git a/Covid19Radar/Covid19Radar.Android/Services/LocalNotificationService.cs b/Covid19Radar/Covid19Radar.Android/Services/LocalNotificationService.cs
index 30f7af8c1..e078a9baf 100644
--- a/Covid19Radar/Covid19Radar.Android/Services/LocalNotificationService.cs
+++ b/Covid19Radar/Covid19Radar.Android/Services/LocalNotificationService.cs
@@ -61,11 +61,13 @@ public async Task ShowExposureNotificationAsync()
_loggerService.StartMethod();
Intent intent = MainActivity.NewIntent(Platform.AppContext, Destination.ContactedNotifyPage);
+ intent.AddFlags(ActivityFlags.ClearTask);
+
PendingIntent pendingIntent = PendingIntent.GetActivity(
Platform.AppContext,
REQUEST_CODE,
intent,
- PendingIntentFlags.UpdateCurrent
+ PendingIntentFlags.CancelCurrent | PendingIntentFlags.Immutable
);
var notification = new NotificationCompat
diff --git a/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj b/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj
index b1b9b51c2..fd414ed44 100644
--- a/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj
+++ b/Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj
@@ -478,12 +478,6 @@
-
-
-
-
-
-
diff --git a/Covid19Radar/Covid19Radar.iOS/Info.plist b/Covid19Radar/Covid19Radar.iOS/Info.plist
index 806a554c6..cfd01d1dc 100644
--- a/Covid19Radar/Covid19Radar.iOS/Info.plist
+++ b/Covid19Radar/Covid19Radar.iOS/Info.plist
@@ -54,7 +54,6 @@
BGTaskSchedulerPermittedIdentifiersAPP_PACKAGE_NAME.exposure-notification
- APP_PACKAGE_NAME.exposure-detectionAPP_PACKAGE_NAME.delete-old-logsUIAppFonts
diff --git a/Covid19Radar/Covid19Radar.iOS/Resources/Base.lproj/TutorialPage50@2x.png b/Covid19Radar/Covid19Radar.iOS/Resources/Base.lproj/TutorialPage50@2x.png
deleted file mode 100644
index 06983ec89..000000000
Binary files a/Covid19Radar/Covid19Radar.iOS/Resources/Base.lproj/TutorialPage50@2x.png and /dev/null differ
diff --git a/Covid19Radar/Covid19Radar.iOS/Resources/Base.lproj/TutorialPage50@3x.png b/Covid19Radar/Covid19Radar.iOS/Resources/Base.lproj/TutorialPage50@3x.png
deleted file mode 100644
index 862ebacf5..000000000
Binary files a/Covid19Radar/Covid19Radar.iOS/Resources/Base.lproj/TutorialPage50@3x.png and /dev/null differ
diff --git a/Covid19Radar/Covid19Radar.iOS/Resources/license.html b/Covid19Radar/Covid19Radar.iOS/Resources/license.html
index 55821a359..6c79a60f4 100644
--- a/Covid19Radar/Covid19Radar.iOS/Resources/license.html
+++ b/Covid19Radar/Covid19Radar.iOS/Resources/license.html
@@ -1167,25 +1167,12 @@
SOFTWARE.
-Xamarin Exposure Notification
+Cappuccino
-
MIT License
-
Copyright (c) Microsoft Corporation.
-
Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE
+
Copyright 2021 Cappuccino Authors
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
FFImageLoading
diff --git a/Covid19Radar/Covid19Radar.iOS/Services/ExposureDetectionBackgroundService.cs b/Covid19Radar/Covid19Radar.iOS/Services/ExposureDetectionBackgroundService.cs
index 22f7520c8..a26764900 100644
--- a/Covid19Radar/Covid19Radar.iOS/Services/ExposureDetectionBackgroundService.cs
+++ b/Covid19Radar/Covid19Radar.iOS/Services/ExposureDetectionBackgroundService.cs
@@ -3,12 +3,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BackgroundTasks;
-using Chino;
using Covid19Radar.Common;
using Covid19Radar.Repository;
using Covid19Radar.Services;
@@ -20,14 +17,17 @@ namespace Covid19Radar.iOS.Services
{
public class ExposureDetectionBackgroundService : AbsExposureDetectionBackgroundService
{
- private static string BGTASK_IDENTIFIER => AppInfo.PackageName + ".exposure-detection";
+ /*
+ * [IMPORTANT]
+ * From README.md( https://developer.apple.com/documentation/exposurenotification/building_an_app_to_notify_users_of_covid-19_exposure )
+ *
+ * The Background Task framework automatically detects apps that contain the Exposure Notification entitlement and a background task that ends in `exposure-notification`.
+ * The operating system automatically launches these apps when they aren't running and guarantees them more background time to ensure that the app can test and report results promptly.
+ */
+ private static string BGTASK_IDENTIFIER => AppInfo.PackageName + ".exposure-notification";
- private const int TIMEOUT_IN_MILLIS = 60 * 60 * 1000;
-
- private readonly AbsExposureNotificationApiService _exposureNotificationApiService;
private readonly ILoggerService _loggerService;
-
public ExposureDetectionBackgroundService(
IDiagnosisKeyRepository diagnosisKeyRepository,
AbsExposureNotificationApiService exposureNotificationApiService,
@@ -48,7 +48,6 @@ IDateTimeUtility dateTimeUtility
dateTimeUtility
)
{
- _exposureNotificationApiService = exposureNotificationApiService;
_loggerService = loggerService;
}
@@ -69,18 +68,6 @@ public override void Schedule()
{
try
{
- IList statuses = _exposureNotificationApiService.GetStatusesAsync()
- .GetAwaiter().GetResult();
-
- bool isUnauthorized = statuses
- .Any(status => status.Code == ExposureNotificationStatus.Code_iOS.Unauthorized);
- if (isUnauthorized)
- {
- _loggerService.Error("Exposure notification is not authorized.");
- task.SetTaskCompleted(true);
- return;
- }
-
await ExposureDetectionAsync(cancellationTokenSource);
task.SetTaskCompleted(true);
}
diff --git a/Covid19Radar/Covid19Radar.iOS/Services/ExposureNotificationApiService.cs b/Covid19Radar/Covid19Radar.iOS/Services/ExposureNotificationApiService.cs
index c9d2cbe4b..ba289c781 100644
--- a/Covid19Radar/Covid19Radar.iOS/Services/ExposureNotificationApiService.cs
+++ b/Covid19Radar/Covid19Radar.iOS/Services/ExposureNotificationApiService.cs
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -14,8 +15,9 @@ namespace Covid19Radar.iOS.Services
{
public class ExposureNotificationApiService : AbsExposureNotificationApiService
{
- private ExposureNotificationClient _exposureNotificationClient = new ExposureNotificationClient();
+ private const int MILLISECONDS_TO_WAIT_DISMISSING_ANIMATION = 1000;
+ private ExposureNotificationClient _exposureNotificationClient = new ExposureNotificationClient();
public string UserExplanation
{
set => _exposureNotificationClient.UserExplanation = value;
@@ -30,8 +32,18 @@ ILoggerService loggerService
public override Task> GetStatusesAsync()
=> _exposureNotificationClient.GetStatusesAsync();
- public override Task> GetTemporaryExposureKeyHistoryAsync()
- => _exposureNotificationClient.GetTemporaryExposureKeyHistoryAsync();
+ public override async Task> GetTemporaryExposureKeyHistoryAsync()
+ {
+ try
+ {
+ return await _exposureNotificationClient.GetTemporaryExposureKeyHistoryAsync();
+ }
+ finally
+ {
+ // [workaround] wait for dismissing en permission modal
+ await Task.Delay(MILLISECONDS_TO_WAIT_DISMISSING_ANIMATION);
+ }
+ }
public override Task GetVersionAsync()
=> _exposureNotificationClient.GetVersionAsync();
diff --git a/Covid19Radar/Covid19Radar/App.xaml.cs b/Covid19Radar/Covid19Radar/App.xaml.cs
index 72da84340..43fcd2bdd 100644
--- a/Covid19Radar/Covid19Radar/App.xaml.cs
+++ b/Covid19Radar/Covid19Radar/App.xaml.cs
@@ -147,7 +147,6 @@ protected override void RegisterTypes(IContainerRegistry containerRegistry)
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
- containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
// Help
@@ -162,7 +161,6 @@ protected override void RegisterTypes(IContainerRegistry containerRegistry)
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
- containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
containerRegistry.RegisterForNavigation();
@@ -202,10 +200,10 @@ private static void RegisterCommonTypes(IContainer container)
#if DEBUG
container.Register(Reuse.Singleton);
- container.Register(Reuse.Singleton);
+ container.Register(Reuse.Singleton);
#else
container.Register(Reuse.Singleton);
- container.Register(Reuse.Singleton);
+ container.Register(Reuse.Singleton);
#endif
container.Register(Reuse.Singleton);
@@ -216,7 +214,12 @@ private static void RegisterCommonTypes(IContainer container)
container.Register(Reuse.Singleton);
container.Register(Reuse.Singleton);
container.Register(Reuse.Singleton);
+
+#if EVENT_LOG_ENABLED
container.Register(Reuse.Singleton);
+#else
+ container.Register(Reuse.Singleton);
+#endif
// Utilities
container.Register(Reuse.Singleton);
diff --git a/Covid19Radar/Covid19Radar/Common/AppConstants.cs b/Covid19Radar/Covid19Radar/Common/AppConstants.cs
index 6cc81e6ce..3db48094e 100644
--- a/Covid19Radar/Covid19Radar/Common/AppConstants.cs
+++ b/Covid19Radar/Covid19Radar/Common/AppConstants.cs
@@ -66,10 +66,5 @@ public static class AppConstants
/// Delay for error in TEK re-registration.
///
public const int DelayForRegistrationErrorMillis = 5000;
-
- ///
- ///
- ///
- public const bool DEFAULT_SEND_EVENT_LOG_ENABLED = true;
}
}
diff --git a/Covid19Radar/Covid19Radar/Common/AppUtils.cs b/Covid19Radar/Covid19Radar/Common/AppUtils.cs
index c1aef1f2c..dad5d39c6 100644
--- a/Covid19Radar/Covid19Radar/Common/AppUtils.cs
+++ b/Covid19Radar/Covid19Radar/Common/AppUtils.cs
@@ -47,7 +47,8 @@ public static async void CheckVersion(ILoggerService loggerService)
try
{
var json = await client.GetStringAsync(uri);
- var versionString = JObject.Parse(json).Value("version");
+ var key = Device.RuntimePlatform == Device.iOS ? "ios" : "android";
+ var versionString = JObject.Parse(json).Value(key);
if (new Version(versionString).CompareTo(new Version(AppInfo.VersionString)) > 0)
{
diff --git a/Covid19Radar/Covid19Radar/Common/DeviceVerifierUtils.cs b/Covid19Radar/Covid19Radar/Common/DeviceVerifierUtils.cs
index 07662fa8f..964bb4a39 100644
--- a/Covid19Radar/Covid19Radar/Common/DeviceVerifierUtils.cs
+++ b/Covid19Radar/Covid19Radar/Common/DeviceVerifierUtils.cs
@@ -12,7 +12,7 @@ namespace Covid19Radar.Common
{
public static class DeviceVerifierUtils
{
- #region V3DiagnosisApi
+ #region V3DiagnosisApi v2.0.0 -
public static byte[] CreateAndroidNonceV3(DiagnosisSubmissionParameter submission)
{
var cleartext = GetNonceClearTextV3(submission);
@@ -54,7 +54,7 @@ static string GetClearText(V1EventLogRequest.EventLog log)
#endregion
- #region V1/V2DiagnosisApi
+ #region V2DiagnosisApi v1.2.2 - v1.4.1
// For checking compatibility with server API, do not remove this method.
public static byte[] CreateAndroidNonceV2(DiagnosisSubmissionParameter submission)
@@ -79,6 +79,31 @@ static string GetRegionString(IEnumerable regions) =>
}
#endregion
+ #region V1DiagnosisApi version v1.0.0 - v1.2.1
+
+ // For checking compatibility with server API, do not remove this method.
+ public static byte[] CreateAndroidNonceV1(DiagnosisSubmissionParameter submission)
+ {
+ var cleartext = GetNonceClearTextV1(submission);
+ var nonce = GetSha256(cleartext);
+ return nonce;
+ }
+
+ public static string GetNonceClearTextV1(DiagnosisSubmissionParameter submission)
+ {
+ return string.Join("|", submission.AppPackageName, GetKeyString(submission.Keys), GetRegionString(submission.Regions), submission.VerificationPayload);
+
+ static string GetKeyString(IEnumerable keys) =>
+ string.Join(",", keys.OrderBy(k => k.KeyData).Select(k => GetKeyStringCore(k)));
+
+ static string GetKeyStringCore(DiagnosisSubmissionParameter.Key k) =>
+ string.Join(".", k.KeyData, k.RollingStartNumber, k.RollingPeriod, 0 /* TransmissionRisk was always 0. */);
+
+ static string GetRegionString(IEnumerable regions) =>
+ string.Join(",", regions.Select(r => r.ToUpperInvariant()).OrderBy(r => r));
+ }
+ #endregion
+
private static byte[] GetSha256(string text)
{
using var sha = SHA256.Create();
diff --git a/Covid19Radar/Covid19Radar/Common/PreferenceKey.cs b/Covid19Radar/Covid19Radar/Common/PreferenceKey.cs
index 4fcd8aeba..71fa689cc 100644
--- a/Covid19Radar/Covid19Radar/Common/PreferenceKey.cs
+++ b/Covid19Radar/Covid19Radar/Common/PreferenceKey.cs
@@ -18,13 +18,13 @@ public static class PreferenceKey
public static string CanConfirmExposure = "CanConfirmExposure";
public static string LastConfirmedDateTimeEpoch = "LastConfirmedDateTimeEpoch";
- public static string IsSendEventLogEnabled = "IsSendEventLogEnabled";
+ public static string SendEventLogState = "SendEventLogState";
public const string DailySummaries = "DailySummaries";
public const string ExposureWindows = "ExposureWindows";
// for ExposureConfigurationRepository
- public const string IsExposureConfigurationUpdated = "IsExposureConfigurationUpdated";
+ public const string IsDiagnosisKeysDataMappingConfigurationUpdated = "IsDiagnosisKeysDataMappingConfigurationUpdated";
public const string ExposureConfigurationDownloadedEpoch = "ExposureConfigurationDownloadedEpoch";
public const string ExposureConfigurationAppliedEpoch = "ExposureConfigurationAppliedEpoch";
diff --git a/Covid19Radar/Covid19Radar/Covid19Radar.csproj b/Covid19Radar/Covid19Radar/Covid19Radar.csproj
index da5ab6bd3..469753f4c 100644
--- a/Covid19Radar/Covid19Radar/Covid19Radar.csproj
+++ b/Covid19Radar/Covid19Radar/Covid19Radar.csproj
@@ -87,9 +87,6 @@
PrivacyPolicyPage2.xaml
-
- ThankYouNotifyOtherPage.xaml
- LicenseAgreementPage.xaml
@@ -99,9 +96,6 @@
NotifyOtherPage.xaml
-
- ExceptionPage.xaml
- SubmitConsentPage.xaml
diff --git a/Covid19Radar/Covid19Radar/IExposureNotificationEventCallback.cs b/Covid19Radar/Covid19Radar/IExposureNotificationEventCallback.cs
index a1cdd1225..d4638b315 100644
--- a/Covid19Radar/Covid19Radar/IExposureNotificationEventCallback.cs
+++ b/Covid19Radar/Covid19Radar/IExposureNotificationEventCallback.cs
@@ -8,7 +8,10 @@ public interface IExposureNotificationEventCallback
{
public void OnEnabled() { }
public void OnDeclined() { }
+
public void OnGetTekHistoryAllowed() { }
+ public void OnGetTekHistoryDecline() { }
+
public void OnPreauthorizeAllowed() { }
}
}
diff --git a/Covid19Radar/Covid19Radar/Model/ExposureCheckScoreModel.cs b/Covid19Radar/Covid19Radar/Model/ExposureCheckScoreModel.cs
deleted file mode 100644
index 0ae7af590..000000000
--- a/Covid19Radar/Covid19Radar/Model/ExposureCheckScoreModel.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at https://mozilla.org/MPL/2.0/.
-using System;
-using System.Globalization;
-
-namespace Covid19Radar.Model
-{
- public class ExposureCheckScoreModel
- {
- public double DailySummaryScoreSum { get; set; }
- public long DateMillisSinceEpoch { get; set; }
-
- public string DateTimeString
- {
- get
- {
- return DateTimeOffset.UnixEpoch
- .AddMilliseconds(DateMillisSinceEpoch).UtcDateTime
- .ToLocalTime().ToString("D", CultureInfo.CurrentCulture);
- }
- }
-
- public string DailySummaryScoreSumString
- {
- get
- {
- return DailySummaryScoreSum.ToString("0.00");
- }
- }
- }
-}
diff --git a/Covid19Radar/Covid19Radar/Model/ExposureRiskCalculationConfiguration.cs b/Covid19Radar/Covid19Radar/Model/ExposureRiskCalculationConfiguration.cs
index 614acb22d..7ea334527 100644
--- a/Covid19Radar/Covid19Radar/Model/ExposureRiskCalculationConfiguration.cs
+++ b/Covid19Radar/Covid19Radar/Model/ExposureRiskCalculationConfiguration.cs
@@ -50,6 +50,9 @@ public override int GetHashCode()
return HashCode.Combine(FormatVersion, DailySummary_DaySummary_ScoreSum, DailySummary_WeightedDurationAverage, ExposureWindow_ScanInstance_SecondsSinceLastScanSum, ExposureWindow_ScanInstance_TypicalAttenuationDb_Max, ExposureWindow_ScanInstance_TypicalAttenuationDb_Min);
}
+ public override string ToString()
+ => JsonConvert.SerializeObject(this);
+
[JsonObject]
public class Threshold
{
@@ -71,6 +74,7 @@ public bool Cond(double value)
{
return Op switch
{
+ OPERATION_NOP => true,
OPERATION_EQUAL => this.Value == value,
OPERATION_GREATER => this.Value < value,
OPERATION_GREATER_EQUAL => this.Value <= value,
diff --git a/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs b/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs
index ea40bf746..4b10c575e 100644
--- a/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs
+++ b/Covid19Radar/Covid19Radar/Repository/DiagnosisKeyRepository.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@@ -16,7 +17,7 @@ namespace Covid19Radar.Repository
{
public interface IDiagnosisKeyRepository
{
- public Task> GetDiagnosisKeysListAsync(string url, CancellationToken cancellationToken);
+ public Task<(HttpStatusCode, IList)> GetDiagnosisKeysListAsync(string url, CancellationToken cancellationToken);
public Task DownloadDiagnosisKeysAsync(DiagnosisKeyEntry diagnosisKeyEntry, string outputDir, CancellationToken cancellationToken);
}
@@ -51,21 +52,22 @@ ILoggerService loggerService
_loggerService = loggerService;
}
- public async Task> GetDiagnosisKeysListAsync(string url, CancellationToken cancellationToken)
+ public async Task<(HttpStatusCode, IList)> GetDiagnosisKeysListAsync(string url, CancellationToken cancellationToken)
{
HttpResponseMessage response = await _httpClient.GetAsync(url, cancellationToken);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
_loggerService.Debug(content);
- return JsonConvert.DeserializeObject>(content);
+
+ return (response.StatusCode, JsonConvert.DeserializeObject>(content));
}
else
{
_loggerService.Debug($"GetDiagnosisKeysListAsync {response.StatusCode}");
}
- return new List();
+ return (response.StatusCode, new List());
}
public async Task DownloadDiagnosisKeysAsync(DiagnosisKeyEntry diagnosisKeyEntry, string outputDir, CancellationToken cancellationToken)
diff --git a/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs b/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs
index 5d632b50c..f65c63d67 100644
--- a/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs
+++ b/Covid19Radar/Covid19Radar/Repository/ExposureConfigurationRepository.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@@ -109,6 +110,8 @@ private async Task GetExposureConfigurationInternalAsync(
currentExposureConfiguration = JsonConvert.DeserializeObject(exposureConfigurationAsJson);
+ _loggerService.Info("Cached:" + exposureConfigurationAsJson);
+
if (!IsDownloadedExposureConfigurationOutdated(AppConstants.ExposureConfigurationFileDownloadCacheRetentionDays))
{
_loggerService.EndMethod();
@@ -131,9 +134,12 @@ private async Task GetExposureConfigurationInternalAsync(
}
}
+ // Cache not exist (first time. probably...)
if (currentExposureConfiguration is null)
{
currentExposureConfiguration = CreateDefaultConfiguration();
+ SetExposureConfigurationDownloadedDateTime(_dateTimeUtility.UtcNow);
+ SetIsDiagnosisKeysDataMappingConfigurationUpdated(true);
}
await _serverConfigurationRepository.LoadAsync();
@@ -145,11 +151,13 @@ private async Task GetExposureConfigurationInternalAsync(
if (response.IsSuccessStatusCode)
{
string exposureConfigurationAsJson = await response.Content.ReadAsStringAsync();
- _loggerService.Debug(exposureConfigurationAsJson);
try
{
newExposureConfiguration = JsonConvert.DeserializeObject(exposureConfigurationAsJson);
+
+ _loggerService.Info("Downloaded:" + exposureConfigurationAsJson);
+
SetExposureConfigurationDownloadedDateTime(_dateTimeUtility.UtcNow);
}
catch (JsonException exception)
@@ -215,14 +223,14 @@ private static ExposureConfiguration CreateDefaultConfiguration()
GoogleDailySummariesConfig = new DailySummariesConfig()
{
AttenuationBucketThresholdDb = new List() {
- 50,
- 54,
+ 46,
+ 60,
65
},
AttenuationBucketWeights = new List() {
+ 1.0,
2.5,
1.3,
- 0.6,
0.01
},
DaysSinceExposureThreshold = 0,
@@ -282,13 +290,13 @@ private static ExposureConfiguration CreateDefaultConfiguration()
InfectiousnessWhenDaysSinceOnsetMissing = Infectiousness.High,
ReportTypeNoneMap = ReportType.ConfirmedTest,
AttenuationDurationThresholds = new int[] {
- 50,
- 54,
+ 46,
+ 60,
65
},
- ImmediateDurationWeight = 250.0,
- NearDurationWeight = 130.0,
- MediumDurationWeight = 60.0,
+ ImmediateDurationWeight = 100.0,
+ NearDurationWeight = 250.0,
+ MediumDurationWeight = 130.0,
OtherDurationWeight = 1.0,
DaysSinceLastExposureThreshold = 0,
InfectiousnessForDaysSinceOnsetOfSymptoms = new Dictionary()
@@ -426,8 +434,8 @@ private static ExposureConfiguration CreateDefaultConfiguration()
},
TransmissionRiskLevelValues = new int[]
{
- 7,
- 7,
+ 0,
+ 0,
7,
7,
7,
@@ -477,13 +485,10 @@ private bool IsUpdatedDiagnosisKeysDataMapping(
ExposureConfiguration exposureConfiguration2
)
{
- return
- (exposureConfiguration1.GoogleDiagnosisKeysDataMappingConfig
- != exposureConfiguration2.GoogleDiagnosisKeysDataMappingConfig)
- ||
- (exposureConfiguration1.AppleExposureConfigV2.InfectiousnessForDaysSinceOnsetOfSymptoms
- != exposureConfiguration2.AppleExposureConfigV2.InfectiousnessForDaysSinceOnsetOfSymptoms);
-
+ var googleDiagnosisKeysDataMappingConfigUpdated = !exposureConfiguration1.GoogleDiagnosisKeysDataMappingConfig.Equals(exposureConfiguration2.GoogleDiagnosisKeysDataMappingConfig);
+ var appleInfectiousnessForDaysSinceOnsetOfSymptoms = !exposureConfiguration1.AppleExposureConfigV2.InfectiousnessForDaysSinceOnsetOfSymptoms
+ .SequenceEqual(exposureConfiguration2.AppleExposureConfigV2.InfectiousnessForDaysSinceOnsetOfSymptoms);
+ return googleDiagnosisKeysDataMappingConfigUpdated || appleInfectiousnessForDaysSinceOnsetOfSymptoms;
}
private bool IsExposureConfigurationOutdated(int retensionDays)
@@ -533,10 +538,10 @@ private void RemoveExposureConfigurationInternal()
}
public void SetIsDiagnosisKeysDataMappingConfigurationUpdated(bool isUpdated)
- => _preferencesService.SetValue(PreferenceKey.IsExposureConfigurationUpdated, isUpdated);
+ => _preferencesService.SetValue(PreferenceKey.IsDiagnosisKeysDataMappingConfigurationUpdated, isUpdated);
public bool IsDiagnosisKeysDataMappingConfigurationUpdated()
- => _preferencesService.GetValue(PreferenceKey.IsExposureConfigurationUpdated, true);
+ => _preferencesService.GetValue(PreferenceKey.IsDiagnosisKeysDataMappingConfigurationUpdated, true);
private void SetExposureConfigurationDownloadedDateTime(DateTime dateTime)
{
diff --git a/Covid19Radar/Covid19Radar/Repository/ExposureDataRepository.cs b/Covid19Radar/Covid19Radar/Repository/ExposureDataRepository.cs
index 5907357ca..095b46126 100644
--- a/Covid19Radar/Covid19Radar/Repository/ExposureDataRepository.cs
+++ b/Covid19Radar/Covid19Radar/Repository/ExposureDataRepository.cs
@@ -2,6 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -18,19 +19,16 @@ public class ExposureDataRepository : IExposureDataRepository
{
private const string EMPTY_LIST_JSON = "[]";
- private readonly IPreferencesService _preferencesService;
private readonly ISecureStorageService _secureStorageService;
private readonly IDateTimeUtility _dateTimeUtility;
private readonly ILoggerService _loggerService;
public ExposureDataRepository(
- IPreferencesService preferencesService,
ISecureStorageService secureStorageService,
IDateTimeUtility dateTimeUtility,
ILoggerService loggerService
)
{
- _preferencesService = preferencesService;
_secureStorageService = secureStorageService;
_dateTimeUtility = dateTimeUtility;
_loggerService = loggerService;
@@ -50,14 +48,50 @@ List exposueWindowList
List existDailySummaryList = await GetDailySummariesAsync();
List existExposureWindowList = await GetExposureWindowsAsync();
- List unionDailySummaryList = existDailySummaryList.Union(dailySummaryList).ToList();
+ List filteredExistDailySummaryList = new List();
+
+ // Filter and merge DailySummaries that have same DateMillisSinceEpoch value.
+ foreach (var existDailySummary in existDailySummaryList)
+ {
+ var conflictDailySummaryList = dailySummaryList
+ .Where(ds => ds.DateMillisSinceEpoch == existDailySummary.DateMillisSinceEpoch)
+ .ToList();
+
+ var conflictDailySummaryListCount = conflictDailySummaryList.Count();
+ if (conflictDailySummaryListCount == 0)
+ {
+ filteredExistDailySummaryList.Add(existDailySummary);
+ continue;
+ }
+ else if (conflictDailySummaryListCount > 1)
+ {
+ _loggerService.Warning($"The list conflictDailySummaryList count should be 1 but {conflictDailySummaryListCount}." +
+ "conflictDailySummaryList will be sorted and selected first value.");
+ conflictDailySummaryList.Sort(_dailySummaryComparer);
+ }
+
+ // `conflictDailySummaryList` count must be 1,
+ // because the DailySummary objects that have same DateMillisSinceEpoch value must be saved after merge.
+ DailySummary newDailySummary = conflictDailySummaryList.First();
+
+ if (existDailySummary.Equals(newDailySummary))
+ {
+ filteredExistDailySummaryList.Add(existDailySummary);
+ }
+ else
+ {
+ MergeDailySummarySelectMaxValues(existDailySummary, newDailySummary);
+ }
+ }
+
+ List unionDailySummaryList = filteredExistDailySummaryList.Union(dailySummaryList).ToList();
List unionExposureWindowList = existExposureWindowList.Union(exposueWindowList).ToList();
unionDailySummaryList.Sort(_dailySummaryComparer);
unionExposureWindowList.Sort(_exposureWindowComparer);
await SaveExposureDataAsync(unionDailySummaryList, unionExposureWindowList);
- List newDailySummaryList = unionDailySummaryList.Except(existDailySummaryList).ToList();
+ List newDailySummaryList = unionDailySummaryList.Except(filteredExistDailySummaryList).ToList();
List newExposureWindowList = unionExposureWindowList.Except(existExposureWindowList).ToList();
_loggerService.EndMethod();
@@ -65,6 +99,79 @@ List exposueWindowList
return (newDailySummaryList, newExposureWindowList);
}
+ ///
+ /// Select and merge the maximum values of each DailySummary objects.
+ ///
+ ///
+ ///
+ private void MergeDailySummarySelectMaxValues(DailySummary from, DailySummary to)
+ {
+ _loggerService.StartMethod();
+
+ if (from.DateMillisSinceEpoch != to.DateMillisSinceEpoch)
+ {
+ _loggerService.Info($"DateMillisSinceEpoch is not match: {from.DateMillisSinceEpoch}, {to.DateMillisSinceEpoch}");
+ return;
+ }
+
+ if (from.DaySummary != null)
+ {
+ if (to.DaySummary == null)
+ {
+ to.DaySummary = new ExposureSummaryData();
+ }
+ to.DaySummary.ScoreSum = Math.Max(from.DaySummary.ScoreSum, to.DaySummary.ScoreSum);
+ to.DaySummary.MaximumScore = Math.Max(from.DaySummary.MaximumScore, to.DaySummary.MaximumScore);
+ to.DaySummary.WeightedDurationSum = Math.Max(from.DaySummary.WeightedDurationSum, to.DaySummary.WeightedDurationSum);
+ }
+
+ if (from.ConfirmedTestSummary != null)
+ {
+ if (to.ConfirmedTestSummary == null)
+ {
+ to.ConfirmedTestSummary = new ExposureSummaryData();
+ }
+ to.ConfirmedTestSummary.ScoreSum = Math.Max(from.ConfirmedTestSummary.ScoreSum, to.ConfirmedTestSummary.ScoreSum);
+ to.ConfirmedTestSummary.MaximumScore = Math.Max(from.ConfirmedTestSummary.MaximumScore, to.ConfirmedTestSummary.MaximumScore);
+ to.ConfirmedTestSummary.WeightedDurationSum = Math.Max(from.ConfirmedTestSummary.WeightedDurationSum, to.ConfirmedTestSummary.WeightedDurationSum);
+ }
+
+ if (from.ConfirmedClinicalDiagnosisSummary != null)
+ {
+ if (to.ConfirmedClinicalDiagnosisSummary == null)
+ {
+ to.ConfirmedClinicalDiagnosisSummary = new ExposureSummaryData();
+ }
+ to.ConfirmedClinicalDiagnosisSummary.ScoreSum = Math.Max(from.ConfirmedClinicalDiagnosisSummary.ScoreSum, to.ConfirmedClinicalDiagnosisSummary.ScoreSum);
+ to.ConfirmedClinicalDiagnosisSummary.MaximumScore = Math.Max(from.ConfirmedClinicalDiagnosisSummary.MaximumScore, to.ConfirmedClinicalDiagnosisSummary.MaximumScore);
+ to.ConfirmedClinicalDiagnosisSummary.WeightedDurationSum = Math.Max(from.ConfirmedClinicalDiagnosisSummary.WeightedDurationSum, to.ConfirmedClinicalDiagnosisSummary.WeightedDurationSum);
+ }
+
+ if (from.SelfReportedSummary != null)
+ {
+ if (to.SelfReportedSummary == null)
+ {
+ to.SelfReportedSummary = new ExposureSummaryData();
+ }
+ to.SelfReportedSummary.ScoreSum = Math.Max(from.SelfReportedSummary.ScoreSum, to.SelfReportedSummary.ScoreSum);
+ to.SelfReportedSummary.MaximumScore = Math.Max(from.SelfReportedSummary.MaximumScore, to.SelfReportedSummary.MaximumScore);
+ to.SelfReportedSummary.WeightedDurationSum = Math.Max(from.SelfReportedSummary.WeightedDurationSum, to.SelfReportedSummary.WeightedDurationSum);
+ }
+
+ if (from.RecursiveSummary != null)
+ {
+ if (to.RecursiveSummary == null)
+ {
+ to.RecursiveSummary = new ExposureSummaryData();
+ }
+ to.RecursiveSummary.ScoreSum = Math.Max(from.RecursiveSummary.ScoreSum, to.RecursiveSummary.ScoreSum);
+ to.RecursiveSummary.MaximumScore = Math.Max(from.RecursiveSummary.MaximumScore, to.RecursiveSummary.MaximumScore);
+ to.RecursiveSummary.WeightedDurationSum = Math.Max(from.RecursiveSummary.WeightedDurationSum, to.RecursiveSummary.WeightedDurationSum);
+ }
+
+ _loggerService.EndMethod();
+ }
+
private Task SaveExposureDataAsync(IList dailySummaryList, IList exposureWindowList)
{
_loggerService.StartMethod();
@@ -74,8 +181,8 @@ private Task SaveExposureDataAsync(IList dailySummaryList, IList> GetDailySummariesAsync()
try
{
- string dailySummariesJson = _preferencesService.GetValue(PreferenceKey.DailySummaries, EMPTY_LIST_JSON);
+ string dailySummariesJson = _secureStorageService.GetValue(PreferenceKey.DailySummaries, EMPTY_LIST_JSON);
return Task.FromResult(
JsonConvert.DeserializeObject>(dailySummariesJson)
);
@@ -114,7 +221,7 @@ public Task> GetExposureWindowsAsync()
try
{
- string exposureWindowListJson = _preferencesService.GetValue(PreferenceKey.ExposureWindows, EMPTY_LIST_JSON);
+ string exposureWindowListJson = _secureStorageService.GetValue(PreferenceKey.ExposureWindows, EMPTY_LIST_JSON);
return Task.FromResult(
JsonConvert.DeserializeObject>(exposureWindowListJson)
);
@@ -138,7 +245,7 @@ public Task RemoveDailySummariesAsync()
try
{
- _preferencesService.RemoveValue(PreferenceKey.DailySummaries);
+ _secureStorageService.RemoveValue(PreferenceKey.DailySummaries);
return Task.CompletedTask;
}
finally
@@ -153,7 +260,7 @@ public Task RemoveExposureWindowsAsync()
try
{
- _preferencesService.RemoveValue(PreferenceKey.ExposureWindows);
+ _secureStorageService.RemoveValue(PreferenceKey.ExposureWindows);
return Task.CompletedTask;
}
finally
diff --git a/Covid19Radar/Covid19Radar/Repository/ExposureDataRepositoryMock.cs b/Covid19Radar/Covid19Radar/Repository/ExposureDataRepositoryMock.cs
index 6436666a7..5dcd73ee2 100644
--- a/Covid19Radar/Covid19Radar/Repository/ExposureDataRepositoryMock.cs
+++ b/Covid19Radar/Covid19Radar/Repository/ExposureDataRepositoryMock.cs
@@ -26,68 +26,64 @@ public class ExposureDataRepositoryMock : IExposureDataRepository
private List dummyDailySummaries = new List()
{
+ //new DailySummary()
+ //{
+ // DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 10), DateTimeKind.Utc).ToUnixEpoch() * 1000,
+ // DaySummary = new ExposureSummaryData()
+ // {
+ // ScoreSum = 1350
+ // }
+ //},
new DailySummary()
{
- DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 10), DateTimeKind.Utc).ToUnixEpoch() * 1000,
+ DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 11), DateTimeKind.Utc).ToUnixEpoch() * 1000,
DaySummary = new ExposureSummaryData()
{
- ScoreSum = 2000.0
+ ScoreSum = 1350
}
},
new DailySummary()
{
- DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 11), DateTimeKind.Utc).ToUnixEpoch() * 1000,
+ DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 12), DateTimeKind.Utc).ToUnixEpoch() * 1000,
DaySummary = new ExposureSummaryData()
{
- ScoreSum = 1999.0
+ ScoreSum = 1000
}
},
};
private List dummyExposureWindows = new List()
{
+ //new ExposureWindow()
+ //{
+ // DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 10), DateTimeKind.Utc).ToUnixEpoch() * 1000,
+ // ScanInstances = new List()
+ // {
+ // new ScanInstance()
+ // {
+ // SecondsSinceLastScan = 1200,
+ // },
+ // }
+ //},
new ExposureWindow()
{
- DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 10), DateTimeKind.Utc).ToUnixEpoch() * 1000,
- ScanInstances = new List()
- {
- new ScanInstance()
- {
- SecondsSinceLastScan = 200,
- },
- new ScanInstance()
- {
- SecondsSinceLastScan = 1800,
- },
- }
- },
- new ExposureWindow()
- {
- DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 10), DateTimeKind.Utc).ToUnixEpoch() * 1000,
+ DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 11), DateTimeKind.Utc).ToUnixEpoch() * 1000,
ScanInstances = new List()
{
new ScanInstance()
{
- SecondsSinceLastScan = 1800,
+ SecondsSinceLastScan = 840,
},
}
},
new ExposureWindow()
{
- DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 11), DateTimeKind.Utc).ToUnixEpoch() * 1000,
+ DateMillisSinceEpoch = DateTime.SpecifyKind(new DateTime(2022, 1, 12), DateTimeKind.Utc).ToUnixEpoch() * 1000,
ScanInstances = new List()
{
new ScanInstance()
{
- SecondsSinceLastScan = 1800,
- },
- new ScanInstance()
- {
- SecondsSinceLastScan = 1800,
- },
- new ScanInstance()
- {
- SecondsSinceLastScan = 1800,
+ SecondsSinceLastScan = 1200,
},
}
},
@@ -95,10 +91,10 @@ public class ExposureDataRepositoryMock : IExposureDataRepository
private List dummyUserExposureInfos = new List()
{
- new UserExposureInfo()
- {
- Timestamp = DateTime.SpecifyKind(new DateTime(2022, 1, 1), DateTimeKind.Utc)
- }
+ //new UserExposureInfo()
+ //{
+ // Timestamp = DateTime.SpecifyKind(new DateTime(2022, 1, 1), DateTimeKind.Utc)
+ //}
};
public Task> GetDailySummariesAsync()
diff --git a/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs b/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs
index acd4b66fc..ea6f24e0f 100644
--- a/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs
+++ b/Covid19Radar/Covid19Radar/Repository/ExposureRiskCalculationConfigurationRepository.cs
@@ -65,6 +65,8 @@ private string PrepareConfigDir()
public async Task GetExposureRiskCalculationConfigurationAsync(bool preferCache)
{
+ _loggerService.StartMethod();
+
await _semaphore.WaitAsync();
try
@@ -73,6 +75,7 @@ public async Task GetExposureRiskCalcula
}
finally
{
+ _loggerService.EndMethod();
_semaphore.Release();
}
}
@@ -110,8 +113,9 @@ private async Task GetExposureRiskCalcul
{
currentConfiguration = CreateDefaultConfiguration();
}
- else if(preferCache)
+ else if (preferCache)
{
+ _loggerService.EndMethod();
return currentConfiguration;
}
@@ -120,25 +124,28 @@ private async Task GetExposureRiskCalcul
V1ExposureRiskCalculationConfiguration newExposureRiskCalculationConfiguration = null;
- var response = await _httpClient.GetAsync(url);
- if (response.IsSuccessStatusCode)
+ try
{
- string exposureRiskCalculationConfigurationAsJson = await response.Content.ReadAsStringAsync();
- _loggerService.Debug(exposureRiskCalculationConfigurationAsJson);
-
- try
+ var response = await _httpClient.GetAsync(url);
+ if (response.IsSuccessStatusCode)
{
- newExposureRiskCalculationConfiguration = JsonConvert.DeserializeObject(exposureRiskCalculationConfigurationAsJson);
+ string exposureRiskCalculationConfigurationAsJson = await response.Content.ReadAsStringAsync();
+ _loggerService.Debug(exposureRiskCalculationConfigurationAsJson);
+ newExposureRiskCalculationConfiguration
+ = JsonConvert.DeserializeObject(exposureRiskCalculationConfigurationAsJson);
}
- catch (JsonException exception)
+ else
{
- _loggerService.Exception("JsonException.", exception);
+ _loggerService.Warning($"Download ExposureRiskCalculationConfiguration failed from {url}");
}
-
}
- else
+ catch (JsonException exception)
+ {
+ _loggerService.Exception("JsonException.", exception);
+ }
+ catch (HttpRequestException exception)
{
- _loggerService.Warning($"Download ExposureRiskCalculationConfiguration failed from {url}");
+ _loggerService.Exception("HttpRequestException.", exception);
}
if (newExposureRiskCalculationConfiguration is null)
@@ -147,17 +154,27 @@ private async Task GetExposureRiskCalcul
return currentConfiguration;
}
+ if (newExposureRiskCalculationConfiguration.Equals(currentConfiguration))
+ {
+ _loggerService.Info("ExposureRiskCalculationConfiguration have not been changed.");
+ _loggerService.EndMethod();
+
+ return currentConfiguration;
+ }
+
+ _loggerService.Info("ExposureRiskCalculationConfiguration have been changed.");
+
string tmpFilePath = Path.Combine(_configDir, Guid.NewGuid().ToString());
try
{
await SaveAsync(
- JsonConvert.SerializeObject(currentConfiguration, Formatting.Indented),
+ JsonConvert.SerializeObject(newExposureRiskCalculationConfiguration, Formatting.Indented),
tmpFilePath
);
Swap(tmpFilePath, _currentPath);
- return currentConfiguration;
+ return newExposureRiskCalculationConfiguration;
}
finally
{
@@ -175,8 +192,13 @@ private static V1ExposureRiskCalculationConfiguration CreateDefaultConfiguration
DailySummary_DaySummary_ScoreSum = new V1ExposureRiskCalculationConfiguration.Threshold()
{
Op = V1ExposureRiskCalculationConfiguration.Threshold.OPERATION_GREATER_EQUAL,
- Value = 1170.0,
- }
+ Value = 1350.0,
+ },
+ ExposureWindow_ScanInstance_SecondsSinceLastScanSum = new V1ExposureRiskCalculationConfiguration.Threshold()
+ {
+ Op = V1ExposureRiskCalculationConfiguration.Threshold.OPERATION_GREATER_EQUAL,
+ Value = 900.0,
+ },
};
}
diff --git a/Covid19Radar/Covid19Radar/Repository/ServerConfigurationRepository.cs b/Covid19Radar/Covid19Radar/Repository/ServerConfigurationRepository.cs
index 854c851b7..6255487db 100644
--- a/Covid19Radar/Covid19Radar/Repository/ServerConfigurationRepository.cs
+++ b/Covid19Radar/Covid19Radar/Repository/ServerConfigurationRepository.cs
@@ -194,6 +194,8 @@ public async Task SaveAsync()
public class ReleaseServerConfigurationRepository : IServerConfigurationRepository
{
+ public const string PLACEHOLDER_REGION = "{region}";
+
public string UserRegisterApiEndpoint
{
get => IServerConfigurationRepository.CombineAsUrl(AppSettings.Instance.ApiUrlBase, "register");
@@ -241,7 +243,12 @@ public string DiagnosisKeyRegisterApiEndpoint
public string DiagnosisKeyListProvideServerEndpoint
{
- get => null;
+ get => IServerConfigurationRepository.CombineAsUrl(
+ AppSettings.Instance.CdnUrlBase,
+ AppSettings.Instance.BlobStorageContainerName,
+ PLACEHOLDER_REGION,
+ "list.json"
+ );
set
{
// Do nothing
diff --git a/Covid19Radar/Covid19Radar/Repository/UserDataRepository.cs b/Covid19Radar/Covid19Radar/Repository/UserDataRepository.cs
index 4374d82d8..75be88db4 100644
--- a/Covid19Radar/Covid19Radar/Repository/UserDataRepository.cs
+++ b/Covid19Radar/Covid19Radar/Repository/UserDataRepository.cs
@@ -41,8 +41,15 @@ public interface IUserDataRepository
Task SetLastProcessDiagnosisKeyTimestampAsync(string region, long timestamp);
Task RemoveLastProcessDiagnosisKeyTimestampAsync();
- void SetIsSendEventLogEnabled(bool isSendLogEnabled);
- bool IsSendEventLogEnabled();
+ void SetSendEventLogState(SendEventLogState sendEventLogState);
+ SendEventLogState GetSendEventLogState();
+ }
+
+ public enum SendEventLogState
+ {
+ NotSet = 0,
+ Disable = -1,
+ Enable = 1
}
public class UserDataRepository : IUserDataRepository
@@ -246,24 +253,25 @@ public void RemoveAllExposureNotificationStatus()
_loggerService.EndMethod();
}
- public void SetIsSendEventLogEnabled(bool isSendEventLogEnabled)
+ public void SetSendEventLogState(SendEventLogState sendEventLogState)
{
_loggerService.StartMethod();
- _preferencesService.SetValue(PreferenceKey.IsSendEventLogEnabled, isSendEventLogEnabled);
+ _preferencesService.SetValue(PreferenceKey.SendEventLogState, (int)sendEventLogState);
_loggerService.EndMethod();
}
- public bool IsSendEventLogEnabled()
+ public SendEventLogState GetSendEventLogState()
{
_loggerService.StartMethod();
try
{
- return _preferencesService.GetValue(
- PreferenceKey.IsSendEventLogEnabled,
- AppConstants.DEFAULT_SEND_EVENT_LOG_ENABLED
+ int state = _preferencesService.GetValue(
+ PreferenceKey.SendEventLogState,
+ (int)SendEventLogState.NotSet
);
+ return (SendEventLogState)state;
}
finally
{
diff --git a/Covid19Radar/Covid19Radar/Resources/AppResources.Designer.cs b/Covid19Radar/Covid19Radar/Resources/AppResources.Designer.cs
index eb2ce7f1c..4ea66a56b 100644
--- a/Covid19Radar/Covid19Radar/Resources/AppResources.Designer.cs
+++ b/Covid19Radar/Covid19Radar/Resources/AppResources.Designer.cs
@@ -197,6 +197,12 @@ public static string HomePageHeader2Description {
}
}
+ public static string Loading {
+ get {
+ return ResourceManager.GetString("Loading", resourceCulture);
+ }
+ }
+
public static string ButtonShare {
get {
return ResourceManager.GetString("ButtonShare", resourceCulture);
@@ -455,12 +461,6 @@ public static string LowRiskContactPageLabel {
}
}
- public static string LowRiskContactPageCountPrefixText {
- get {
- return ResourceManager.GetString("LowRiskContactPageCountPrefixText", resourceCulture);
- }
- }
-
public static string LowRiskContactPageCountSuffixHoursText {
get {
return ResourceManager.GetString("LowRiskContactPageCountSuffixHoursText", resourceCulture);
@@ -485,45 +485,51 @@ public static string LowRiskContactPageHeaderTextPrefix {
}
}
- public static string LowRiskContactPageHeaderTextSuffix {
+ public static string LowRiskContactPage_DailySummary_ScoreSum_Descritpion_Satisfied {
get {
- return ResourceManager.GetString("LowRiskContactPageHeaderTextSuffix", resourceCulture);
+ return ResourceManager.GetString("LowRiskContactPage_DailySummary_ScoreSum_Descritpion_Satisfied", resourceCulture);
}
}
- public static string LowRiskContactPageAnnotationDecription {
+ public static string LowRiskContactPage_DailySummary_ScoreSum_Descritpion_Unsatisfied {
get {
- return ResourceManager.GetString("LowRiskContactPageAnnotationDecription", resourceCulture);
+ return ResourceManager.GetString("LowRiskContactPage_DailySummary_ScoreSum_Descritpion_Unsatisfied", resourceCulture);
}
}
- public static string NoRiskContactPageLabel {
+ public static string LowRiskContactPage_ExposureDuration_Description_Satisfied {
get {
- return ResourceManager.GetString("NoRiskContactPageLabel", resourceCulture);
+ return ResourceManager.GetString("LowRiskContactPage_ExposureDuration_Description_Satisfied", resourceCulture);
}
}
- public static string NoRiskContactPageDescription {
+ public static string LowRiskContactPage_ExposureDuration_Description_Unsatisfied {
get {
- return ResourceManager.GetString("NoRiskContactPageDescription", resourceCulture);
+ return ResourceManager.GetString("LowRiskContactPage_ExposureDuration_Description_Unsatisfied", resourceCulture);
}
}
- public static string NoRiskContactPageButtonText {
+ public static string LowRiskContactPageAnnotationDecription {
get {
- return ResourceManager.GetString("NoRiskContactPageButtonText", resourceCulture);
+ return ResourceManager.GetString("LowRiskContactPageAnnotationDecription", resourceCulture);
+ }
+ }
+
+ public static string NoRiskContactPageLabel {
+ get {
+ return ResourceManager.GetString("NoRiskContactPageLabel", resourceCulture);
}
}
- public static string ThankYouNotifyOtherPageLabel1 {
+ public static string NoRiskContactPageDescription {
get {
- return ResourceManager.GetString("ThankYouNotifyOtherPageLabel1", resourceCulture);
+ return ResourceManager.GetString("NoRiskContactPageDescription", resourceCulture);
}
}
- public static string ThankYouNotifyOtherPageDescription1 {
+ public static string NoRiskContactPageButtonText {
get {
- return ResourceManager.GetString("ThankYouNotifyOtherPageDescription1", resourceCulture);
+ return ResourceManager.GetString("NoRiskContactPageButtonText", resourceCulture);
}
}
@@ -629,6 +635,18 @@ public static string HomePageTitle1 {
}
}
+ public static string HomePageDialogExceptionTitle {
+ get {
+ return ResourceManager.GetString("HomePageDialogExceptionTitle", resourceCulture);
+ }
+ }
+
+ public static string HomePageDialogExceptionDescription {
+ get {
+ return ResourceManager.GetString("HomePageDialogExceptionDescription", resourceCulture);
+ }
+ }
+
public static string TermsofservicePageTitle {
get {
return ResourceManager.GetString("TermsofservicePageTitle", resourceCulture);
@@ -671,36 +689,6 @@ public static string TutorialPage2Title {
}
}
- public static string TutorialPage5Description1 {
- get {
- return ResourceManager.GetString("TutorialPage5Description1", resourceCulture);
- }
- }
-
- public static string TutorialPage5Description2 {
- get {
- return ResourceManager.GetString("TutorialPage5Description2", resourceCulture);
- }
- }
-
- public static string TutorialPage5Description3 {
- get {
- return ResourceManager.GetString("TutorialPage5Description3", resourceCulture);
- }
- }
-
- public static string TutorialPage5Description4 {
- get {
- return ResourceManager.GetString("TutorialPage5Description4", resourceCulture);
- }
- }
-
- public static string TutorialPage5Title {
- get {
- return ResourceManager.GetString("TutorialPage5Title", resourceCulture);
- }
- }
-
public static string MenuPageTitle {
get {
return ResourceManager.GetString("MenuPageTitle", resourceCulture);
@@ -941,6 +929,12 @@ public static string ExposureNotificationHandler2ErrorMessage {
}
}
+ public static string NotifyOther_Dialog_NoConnection {
+ get {
+ return ResourceManager.GetString("NotifyOther_Dialog_NoConnection", resourceCulture);
+ }
+ }
+
public static string NotifyOtherPageDiag1Message {
get {
return ResourceManager.GetString("NotifyOtherPageDiag1Message", resourceCulture);
@@ -1241,6 +1235,30 @@ public static string InquiryMailSubject {
}
}
+ public static string InquiryMailModelTitle {
+ get {
+ return ResourceManager.GetString("InquiryMailModelTitle", resourceCulture);
+ }
+ }
+
+ public static string InquiryMailOSTitle {
+ get {
+ return ResourceManager.GetString("InquiryMailOSTitle", resourceCulture);
+ }
+ }
+
+ public static string InquiryMailOSVersionTitle {
+ get {
+ return ResourceManager.GetString("InquiryMailOSVersionTitle", resourceCulture);
+ }
+ }
+
+ public static string InquiryMailAppVersionTitle {
+ get {
+ return ResourceManager.GetString("InquiryMailAppVersionTitle", resourceCulture);
+ }
+ }
+
public static string Processing {
get {
return ResourceManager.GetString("Processing", resourceCulture);
@@ -1822,5 +1840,35 @@ public static string ExposurePageExposureDuration {
return ResourceManager.GetString("ExposurePageExposureDuration", resourceCulture);
}
}
+
+ public static string ThresholdTextOperatorGt {
+ get {
+ return ResourceManager.GetString("ThresholdTextOperatorGt", resourceCulture);
+ }
+ }
+
+ public static string ThresholdTextOperatorLt {
+ get {
+ return ResourceManager.GetString("ThresholdTextOperatorLt", resourceCulture);
+ }
+ }
+
+ public static string ThresholdTextOperatorGte {
+ get {
+ return ResourceManager.GetString("ThresholdTextOperatorGte", resourceCulture);
+ }
+ }
+
+ public static string ThresholdTextOperatorLte {
+ get {
+ return ResourceManager.GetString("ThresholdTextOperatorLte", resourceCulture);
+ }
+ }
+
+ public static string ThresholdTextOperatorEqual {
+ get {
+ return ResourceManager.GetString("ThresholdTextOperatorEqual", resourceCulture);
+ }
+ }
}
}
diff --git a/Covid19Radar/Covid19Radar/Resources/AppResources.ja.resx b/Covid19Radar/Covid19Radar/Resources/AppResources.ja.resx
index d63bb05c8..ac7720826 100644
--- a/Covid19Radar/Covid19Radar/Resources/AppResources.ja.resx
+++ b/Covid19Radar/Covid19Radar/Resources/AppResources.ja.resx
@@ -88,6 +88,10 @@
削除しています
+
+ 読み込み中
+ 読み込み中
+
共有する
@@ -250,9 +254,21 @@
陽性登録者のスマートフォンから受信した信号は基準値を下回っていました陽性登録者のスマートフォンから受信した信号は基準値を下回っていました
-
- 直近14日間に合計
- 直近14日間に合計
+
+ スコア: {0:#.##}
+ スコア: {0:#.##}
+
+
+ スコア: {0:#.##}
+ スコア: {0:#.##}
+
+
+ {0:#}分間の接触
+ {0:#}分間の接触
+
+
+ {0:#}分間の接触のため通知の対象外
+ {0:#}分間の接触のため通知の対象外時間
@@ -267,16 +283,12 @@
陽性登録者のスマートフォンの信号を受信しましたが、基準値を超える信号はありません。行動圏内には陽性登録者がいましたので、引き続き感染予防に留意しながらお過ごし下さい。
- スコア
- スコア
-
-
- (1170以上が接触の可能性の通知対象)
- (1170以上が接触の可能性の通知対象)
+ 受信した信号
+ 受信した信号
- ※スコアは、受信した信号の強さと時間から算出しています。1m以内・15分以上の接触で 1170 以上になるように設定しています。
- ※スコアは、受信した信号の強さと時間から算出しています。1m以内・15分以上の接触で 1170 以上になるように設定しています。
+ ※スコアは、受信した信号の強さと時間から算出しています。一般的な条件では1m以内・15分以上の接触で {0:#} {1:#}になるように設定しています。
+ ※スコアは、受信した信号の強さと時間から算出しています。一般的な条件では1m以内・15分以上の接触で {0:#} {1:#}になるように設定しています。陽性登録者のスマートフォンからの信号を受信していません
@@ -290,14 +302,6 @@
アプリを周りの人に知らせるアプリを周りの人に知らせる
-
- 陽性のご登録をいただきありがとうございました
- 陽性のご登録をいただきありがとうございました
-
-
- 登録は匿名で行われ、氏名や連絡先など個人が特定される情報を登録する必要はありません。また、接触した場所の位置情報が記録や通知されることもありません。
- 登録は匿名で行われ、氏名や連絡先など個人が特定される情報を登録する必要はありません。また、接触した場所の位置情報が記録や通知されることもありません。
-
利用規約利用規約
@@ -366,6 +370,14 @@
ホームホーム
+
+ 確認画面へのアクセスに失敗しました
+ 確認画面へのアクセスに失敗しました
+
+
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+
利用規約利用規約
@@ -379,8 +391,8 @@
氏名・電話番号などの個人情報や、GPS(※)などスマートフォンの位置情報を使うことはなく、記録されることもありません。
- 接触の記録は、暗号化され、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が暗号化された情報を利用して接触歴を把握することはありません。
- 接触の記録は、暗号化され、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が暗号化された情報を利用して接触歴を把握することはありません。
+ 接触の記録は、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が情報を利用して接触歴を把握することはありません。
+ 接触の記録は、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が情報を利用して接触歴を把握することはありません。接触の記録はいつでも止めることができます。アプリ内の設定を無効にするか、アプリを削除してください。
@@ -394,26 +406,6 @@
プライバシーについてプライバシーについて
-
- 通知をご利用いただくために
- 通知をご利用いただくために
-
-
- 本アプリで接触の通知をご利用いただくために、本アプリのプッシュ通知を有効にしてください。
- 本アプリで接触の通知をご利用いただくために、本アプリのプッシュ通知を有効にしてください。
-
-
- 有効にする
- 有効にする
-
-
- あとで設定する
- あとで設定する
-
-
- 通知をご利用いただくために
- 通知をご利用いただくために
-
登録する登録する
@@ -583,6 +575,10 @@
センターに接続できませんセンターに接続できません
+
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+
よろしいですか?よろしいですか?
@@ -612,8 +608,8 @@
処理番号は半角数字で入力してください。
- 陽性記録の登録を行う為にCOVID-19接触のログ記録を有効にする必要があります、アプリかOSの設定から有効にしてください。
- 陽性記録の登録を行う為にCOVID-19接触のログ記録を有効にする必要があります、アプリかOSの設定から有効にしてください。
+ 陽性記録の登録を行うために接触通知を有効にする必要があります、アプリかOSの設定から有効にしてください。
+ 陽性記録の登録を行うために接触通知を有効にする必要があります、アプリかOSの設定から有効にしてください。COVID-19接触のログ記録を有効にしてください
@@ -790,13 +786,29 @@
送信エラー
- お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n
- お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n
+ お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n\r\n----以下は削除しないでください----\r\n
+ お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n\r\n----以下は削除しないでください----\r\n接触確認アプリに関するお問い合わせ接触確認アプリに関するお問い合わせ
+
+ モデル名:
+ モデル名:(サポートが見る文言なので常に日本語とする)
+
+
+ OS:
+ OS:(サポートが見る文言なので常に日本語とする)
+
+
+ OSバージョン:
+ OSバージョン:(サポートが見る文言なので常に日本語とする)
+
+
+ アプリバージョン:
+ アプリバージョン:(サポートが見る文言なので常に日本語とする)
+
動作情報ID:動作情報ID:
@@ -1184,4 +1196,26 @@
{0:#}分間の接触{0:#}分間の接触
+
+
+ を超える値
+ を超える値
+
+
+ 未満
+ 未満
+
+
+ 以上
+ 以上
+
+
+ 以下
+ 以下
+
+
+ と同じ
+ と同じ
+
+
diff --git a/Covid19Radar/Covid19Radar/Resources/AppResources.resx b/Covid19Radar/Covid19Radar/Resources/AppResources.resx
index afda4e6aa..290920bd5 100644
--- a/Covid19Radar/Covid19Radar/Resources/AppResources.resx
+++ b/Covid19Radar/Covid19Radar/Resources/AppResources.resx
@@ -214,6 +214,10 @@
Help protect your family and friends by anonymously registering test results.周りの人達を守るために匿名での陽性登録へのご協力をお願いいたします。
+
+ Loading
+ 読み込み中
+
Share
@@ -377,12 +381,8 @@
アプリを周りの人に知らせる
- A low risk signal has been recieved
- 陽性登録者とリスクが極めて低い接触がありました
-
-
- In the last 14 days,
- 直近14日間に合計
+ The signal received from the smartphone of the person who has registered as positive for COVID-19 was below the standard value
+ 陽性登録者のスマートフォンから受信した信号は基準値を下回っていましたh
@@ -393,41 +393,45 @@
分
- A signal has been recieved from COVID-19 positive users. But it is few meters away and has no risk. Please stay with preventing Infection.
- 陽性登録者のスマートフォンの信号を受信しましたが、数m以上離れておりリスクはありません。行動圏内には陽性登録者がいましたので、引き続き感染予防に留意しながらお過ごし下さい。
+ A signal from the smartphone of a person who has registered as positive for COVID-19 was received. However, the signal did not exceed the standard value. There was a person who has registered positive for COVID-19 within your sphere of activities. Therefore, please continue to pay attention to preventing COVID-19 infections.
+ 陽性登録者のスマートフォンの信号を受信しましたが、基準値を超える信号はありません。行動圏内には陽性登録者がいましたので、引き続き感染予防に留意しながらお過ごし下さい。
- Score
- スコア
+ Received signal
+ 受信した信号
+
+
+ Score: {0:#.##}
+ スコア: {0:#.##}
-
- (Possibility of close contact is 20.0 or more)
- (20.0以上が濃厚接触の可能性の通知対象)
+
+ Score: {0:#.##}
+ スコア: {0:#.##}
+
+
+ {0:#} minutes of contact
+ {0:#}分間の接触
+
+
+ Not subject to notification because it was contact for {0:#} minutes
+ {0:#}分間の接触のため通知の対象外
- ※Score is calculated with signal strength and reception time. When you contact with a positive user for 15 minutes within 1 meter, It will be over 20.0.
- ※スコアは、信号強度と受信時間を元に算出されており、1m以内・15分以上の接触があると20.0以上になります。
+ *The score is calculated based on the strength and time of the received signal. It is set to be {0:#} {1:#} with contact within 1 m for 15 minutes or more under regular conditions.
+ ※スコアは、受信した信号の強さと時間から算出しています。1m以内・15分以上の接触で {0:#} {1:#}になるように設定しています。
- No contact has been received with COVID-19 positive users for 14 days.
- 14日間のうちに、リスクが低いものを含め陽性登録者との接触はありません
+ No signal has being received from the smartphone of a person who has registered positive for COVID-19
+ 陽性登録者のスマートフォンからの信号を受信していません
- There is no positive user in your territory so far. Please stay with preventing Infection.
+ It appears there have been no persons who have registered positive for COVID-19 within your sphere of activities. Please continue to pay attention to preventing COVID-19 infections.行動圏内には、陽性登録者はいなかったようです。引き続き感染予防に留意しながらお過ごしください。Share this appアプリを周りの人に知らせる
-
- Thank you for registering your test results!
- 陽性のご登録をいただきありがとうございました
-
-
- Registration is anonymous. You do not have to enter your name or any other personal information. No information regarding location of close contact is recorded.
- 登録は匿名で行われ、氏名や連絡先など個人が特定される情報を登録する必要はありません。また、接触した場所の位置情報が記録や通知されることもありません。
-
Terms of use利用規約
@@ -489,13 +493,21 @@
アプリを周りの人に知らせる
- Status of exposure check
- 接触確認の動作状況
+ There is no signal exceeding the standard value
+ 基準値を超える信号はありませんHomeホーム
+
+ Failed to access the confirmation screen
+ 確認画面へのアクセスに失敗しました
+
+
+ We apologize for the inconvenience. The network may be unstable or the server may be busy. Please try again later.
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+
Term of use利用規約
@@ -509,8 +521,8 @@
氏名・電話番号などの個人情報や、GPSなどスマートフォンの位置情報を使うことはなく、記録されることもありません。
- All data is encrypted and saved locally on your smartphone. All data is automatically deleted after 14 days. Your movements are not tracked in any way by government agencies or third parties.
- 接触の記録は、暗号化され、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が暗号化された情報を利用して接触歴を把握することはありません。
+ All data is saved locally on your smartphone. All data is automatically deleted after 14 days. Your movements are not tracked in any way by government agencies or third parties.
+ 接触の記録は、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が情報を利用して接触歴を把握することはありません。You can stop recording close contacts with other users anytime by changing app settings or deleting the app.
@@ -524,26 +536,6 @@
TutorialPage2Description1プライバシーについて
-
- Turn on notifications
- 通知をご利用いただくために
-
-
- Please turn on notifications to be notified when you had close contacts with COVID-19 positive users.
- 本アプリで接触の通知をご利用いただくために、本アプリのプッシュ通知を有効にしてください。
-
-
- Turn on
- 有効にする
-
-
- Set up later
- あとで設定する
-
-
- To use notifications
- 通知をご利用いただくために
-
Menuメニュー
@@ -701,6 +693,10 @@
Cannot connect to registration centerセンターに接続できません
+
+ We apologize for the inconvinience. The network may be unstable or the server may be busy. Please try again later.
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+
Do you want to register it?よろしいですか?
@@ -730,8 +726,8 @@
処理番号は半角数字で入力してください。
- In order to register positive records, it is necessary to enable COVID-19 contact log recording, please enable it from the application or OS settings.
- 陽性記録の登録を行う為にCOVID-19接触のログ記録を有効にする必要があります、アプリかOSの設定から有効にしてください。
+ In order to register positive records, it is necessary to enable contact notification, please enable it from the application or OS settings.
+ 陽性記録の登録を行う為に接触通知を有効にする必要があります、アプリかOSの設定から有効にしてください。Enable COVID-19 contact logging
@@ -896,13 +892,29 @@ please follow the app. guidance and check the Consultation Centers List to recei
動作情報の送信に失敗しました
- Content of inquiry:\r\n\r\n\r\n\r\n※You do not need to enter personal information such as your name and phone number.\r\n
- お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n
+ Content of inquiry:\r\n\r\n\r\n\r\n※You do not need to enter personal information such as your name and phone number.\r\n\r\n----Don't delete a section below.----\r\n
+ お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n\r\n----以下は削除しないでください----\r\nInquiries about contact information app接触確認アプリに関するお問い合わせ
+
+ モデル名:
+ モデル名:(サポートが見る文言なので常に日本語とする)
+
+
+ OS:
+ OS:(サポートが見る文言なので常に日本語とする)
+
+
+ OSバージョン:
+ OSバージョン:(サポートが見る文言なので常に日本語とする)
+
+
+ アプリバージョン:
+ アプリバージョン:(サポートが見る文言なので常に日本語とする)
+
Processing処理中
@@ -1266,6 +1278,7 @@ Note: this app does not collect users’ location information.
日本語のみ:「陽性者との接触確認」画面のイメージ画像
+
Before {0}年月日以前
@@ -1283,15 +1296,37 @@ Note: this app does not collect users’ location information.
年月日以降
- Total {1:#} min exposure in 1 day
+ A total of {1:#} minutes of contact over 1 day{0}日間に合計{1:#}分間の接触
- Total {1:#} min exposure in {0} days
+ A total of {1:#} minutes of contact over {0} days{0}日間に合計{1:#}分間の接触
- {0:#} min exposure
+ {0:#} minutes of contact{0:#}分間の接触
+
+
+ over
+ を超える値
+
+
+ under
+ 未満
+
+
+ or more
+ 以上
+
+
+ or less
+ 以下
+
+
+
+ と同じ
+
+
diff --git a/Covid19Radar/Covid19Radar/Resources/AppResources.zh-Hans.resx b/Covid19Radar/Covid19Radar/Resources/AppResources.zh-Hans.resx
index 4ab27e30c..ebf23ff10 100644
--- a/Covid19Radar/Covid19Radar/Resources/AppResources.zh-Hans.resx
+++ b/Covid19Radar/Covid19Radar/Resources/AppResources.zh-Hans.resx
@@ -98,6 +98,10 @@
正在删除
+
+ 处理中
+ 読み込み中
+
共享
@@ -269,14 +273,26 @@
アプリを周りの人に知らせる
- 与阳性注册者接触的风险非常低
- 陽性登録者とリスクが極めて低い接触がありました
+ 来自阳性登记者所持智能手机的信号低于基准值
+ 陽性登録者のスマートフォンから受信した信号は基準値を下回っていました
+
+
+ 分数: {0:#.##}
+ スコア: {0:#.##}
+
+
+ 分数: {0:#.##}
+ スコア: {0:#.##}
+
+
+ 接触时间为{0:#}分钟
+ {0:#}分間の接触
-
- 过去14天总共
- 直近14日間に合計
+
+ 接触时间为{0:#}分钟,因此不进行通知推送
+ {0:#}分間の接触のため通知の対象外
-
+
小时時間
@@ -285,41 +301,29 @@
分
- 我收到了阳性注册人的智能手机的信号,但没有风险,因为它在几米之外。活动区域有阳性登记者,请继续注意预防感染。
- 陽性登録者のスマートフォンの信号を受信しましたが、数m以上離れておりリスクはありません。行動圏内には陽性登録者がいましたので、引き続き感染予防に留意しながらお過ごし下さい。
+ 收到了来自阳性登记者所持智能手机的信号,但是信号强度并未超出基准值。您的行动范围内有阳性登记者,请继续注意防止感染。
+ 陽性登録者のスマートフォンの信号を受信しましたが、基準値を超える信号はありません。行動圏内には陽性登録者がいましたので、引き続き感染予防に留意しながらお過ごし下さい。
- 分数
- スコア
-
-
- (20.0以上以告知密切接触的可能性为准)
- (20.0以上が濃厚接触の可能性の通知対象)
+ 收到的信号
+ 受信した信号
- ※核心是根据信号强度和接收时间计算的,如果在 1m 范围内有接触并持续 15 分钟或更长时间,则为 20.0 或更多。
- ※スコアは、信号強度と受信時間を元に算出されており、1m以内・15分以上の接触があると20.0以上になります。
+ ※总和是根据所收到的信号的强度和时间计算的。一般条件下,1米以内、15分钟以上的接触设定为{0:#}{1:#}。
+ ※スコアは、受信した信号の強さと時間から算出しています。一般的な条件では1m以内・15分以上の接触で {0:#} {1:#}になるように設定しています。
- 不接触阳性注册者,包括低风险者
+ 未收到来自阳性登记者所持智能手机的信号リスクが低いものを含め陽性登録者との接触はありません
- 似乎在行动领域没有积极的注册人。 请继续注意预防感染。
+ 您的行动范围内似乎没有阳性登记者。请继续注意防止感染。行動圏内には、陽性登録者はいなかったようです。引き続き感染予防に留意しながらお過ごしください。分享此APPアプリを周りの人に知らせる
-
- 感谢提供检查结果
- 陽性のご登録をいただきありがとうございました
-
-
- 本次注册为匿名注册,您不必输入姓名或任何其他个人信息。另外,该应用不会记录并通知密切接触的地点信息。
- 登録は匿名で行われ、氏名や連絡先など個人が特定される情報を登録する必要はありません。また、接触した場所の位置情報が記録や通知されることもありません。
-
使用条款利用規約
@@ -385,13 +389,21 @@
アプリを周りの人に知らせる
- 联系确认的操作状态
- 接触確認の動作状況
+ 不存在高于基准值的信号
+ 基準値を超える信号はありません主页ホーム
+
+ 问确认界面失败
+ 確認画面へのアクセスに失敗しました
+
+
+ 给您造成不便我们深感抱歉。可能由于网络不稳定或服务器繁忙。请您稍后重试。
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+
使用条款利用規約
@@ -405,8 +417,8 @@
氏名・電話番号などの個人情報や、GPSなどスマートフォンの位置情報を使うことはなく、記録されることもありません。
- 所有数据都会加密并保存在手机本地存储,所有数据14天后会自动删除。政府机构或第三方机构不会以任何方式跟踪监视您的手机
- 接触の記録は、暗号化され、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が暗号化された情報を利用して接触歴を把握することはありません。
+ 所有数据都会保存在手机本地存储,所有数据14天后会自动删除。政府机构或第三方机构不会以任何方式跟踪监视您的手机
+ 接触の記録は、あなたのスマートフォンの中にのみ記録され、14日後に自動的に削除されます。行政機関や第三者が情報を利用して接触歴を把握することはありません。您可以随时停止APP的记录,在设置内设为关闭,或者删掉APP
@@ -420,26 +432,6 @@
关于隐私保护プライバシーについて
-
- 开启接收通知
- 通知をご利用いただくために
-
-
- 为了即时收到密切接触信息,请开启新消息通知
- 本アプリで接触の通知をご利用いただくために、本アプリのプッシュ通知を有効にしてください。
-
-
- 开启
- 有効にする
-
-
- 稍后设置
- あとで設定する
-
-
- To use notifications
- 通知をご利用いただくために
-
菜单メニュー
@@ -589,6 +581,10 @@
无法连接到登记服务中心センターに接続できません
+
+ 给您造成不便我们深感抱歉。可能由于网络不稳定或服务器繁忙。请您稍后重试。
+ ご不便おかけして申し訳ありません。ネットワークが不安定か、サーバーが混み合っている可能性があります。時間をおいて再度お試しください。
+
是否登记?よろしいですか?
@@ -618,8 +614,8 @@
処理番号は半角数字で入力してください。
- 必须启用 COVID-19 接触日志才可进行阳性登记,请在应用或系统设置中启用设定。
- 陽性記録の登録を行う為にCOVID-19接触のログ記録を有効にする必要があります、アプリかOSの設定から有効にしてください。
+ 必须启用 接触通知,请在应用或系统设置中启用设定。
+ 陽性記録の登録を行う為に接触通知を有効にする必要があります、アプリかOSの設定から有効にしてください。请启用 COVID-19 接触日志
@@ -798,13 +794,29 @@
送信エラー
- 意见反馈正文:\r\n\r\n\r\n\r\n※您无需输入个人信息,例如姓名和电话号码。\r\n
- お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n
+ 意见反馈正文:\r\n\r\n\r\n\r\n※您无需输入个人信息,例如姓名和电话号码。\r\n\r\n----请不要删除下面的部分----\r\n
+ お問い合わせ本文:\r\n\r\n\r\n\r\n※氏名、電話番号などの個人情報を記入する必要はありません。\r\n\r\n----以下は削除しないでください----\r\nCocoa的意见反馈接触確認アプリに関するお問い合わせ
+
+ モデル名:
+ モデル名:(サポートが見る文言なので常に日本語とする)
+
+
+ OS:
+ OS:(サポートが見る文言なので常に日本語とする)
+
+
+ OSバージョン:
+ OSバージョン:(サポートが見る文言なので常に日本語とする)
+
+
+ アプリバージョン:
+ アプリバージョン:(サポートが見る文言なので常に日本語とする)
+
操作信息ID:動作情報ID:
@@ -1164,4 +1176,55 @@
日本語のみ:「陽性者との接触確認」画面のイメージ画像
+
+
+ {0}以前
+ 年月日以前
+
+
+ 1 件
+ 1 件
+
+
+ {0} 件
+ {0} 件
+
+
+ {0}以降
+ 年月日以降
+
+
+ 1天内共有{1:#}分钟的接触
+ 1日間に合計{1:#}分間の接触
+
+
+ {0}天内共有{1:#}分钟的接触
+ {0}日間に合計{1:#}分間の接触
+
+
+ {0:#}分钟的接触
+ {0:#}分間の接触
+
+
+
+ 超出
+ を超える値
+
+
+ 少于
+ 未満
+
+
+ 以上
+ 以上
+
+
+ 以下
+ 以下
+
+
+ 等于
+ と同じ
+
+
diff --git a/Covid19Radar/Covid19Radar/Services/AbsExposureDetectionBackgroundService.cs b/Covid19Radar/Covid19Radar/Services/AbsExposureDetectionBackgroundService.cs
index cb501adc5..d8706e034 100644
--- a/Covid19Radar/Covid19Radar/Services/AbsExposureDetectionBackgroundService.cs
+++ b/Covid19Radar/Covid19Radar/Services/AbsExposureDetectionBackgroundService.cs
@@ -11,6 +11,8 @@
using Covid19Radar.Repository;
using Covid19Radar.Services.Logs;
using Covid19Radar.Common;
+using Chino;
+using System.Net;
namespace Covid19Radar.Services
{
@@ -56,32 +58,70 @@ public virtual async Task ExposureDetectionAsync(CancellationTokenSource cancell
{
await _semaphore.WaitAsync();
+ _loggerService.StartMethod();
+
try
{
await InternalExposureDetectionAsync(cancellationTokenSource);
}
finally
{
+ _loggerService.EndMethod();
+
_semaphore.Release();
}
}
private async Task InternalExposureDetectionAsync(CancellationTokenSource cancellationTokenSource = null)
{
+ bool isEnabled = await _exposureNotificationApiService.IsEnabledAsync();
+ if (!isEnabled)
+ {
+ _loggerService.Info($"EN API is not enabled.");
+ return;
+ }
+
+ IEnumerable statuseCodes = await _exposureNotificationApiService.GetStatusCodesAsync();
+
+ bool isActivated = statuseCodes.Contains(ExposureNotificationStatus.Code_Android.ACTIVATED)
+ | statuseCodes.Contains(ExposureNotificationStatus.Code_iOS.Active);
+
+ if (!isActivated)
+ {
+ _loggerService.Info($"EN API is not ACTIVATED.");
+ return;
+ }
+
var cancellationToken = cancellationTokenSource?.Token ?? default(CancellationToken);
await _serverConfigurationRepository.LoadAsync();
+ bool canConfirmExposure = true;
+
foreach (var region in _serverConfigurationRepository.Regions)
{
+ _loggerService.Info($"Region: {region}");
+
var diagnosisKeyListProvideServerUrl = _serverConfigurationRepository.GetDiagnosisKeyListProvideServerUrl(region);
+ _loggerService.Info($"diagnosisKeyListProvideServerUrl: {diagnosisKeyListProvideServerUrl}");
+
List downloadedFileNameList = new List();
try
{
var tmpDir = PrepareDir(region);
- var diagnosisKeyEntryList = await _diagnosisKeyRepository.GetDiagnosisKeysListAsync(diagnosisKeyListProvideServerUrl, cancellationToken);
+ var (httpStatus, diagnosisKeyEntryList) = await _diagnosisKeyRepository.GetDiagnosisKeysListAsync(
+ diagnosisKeyListProvideServerUrl,
+ cancellationToken
+ );
+
+ if (httpStatus != HttpStatusCode.OK)
+ {
+ _loggerService.Info($"URL: {diagnosisKeyListProvideServerUrl}, Response StatusCode: {httpStatus}");
+ canConfirmExposure = false;
+ continue;
+ }
var lastProcessTimestamp = await _userDataRepository.GetLastProcessDiagnosisKeyTimestampAsync(region);
_loggerService.Info($"Region: {region}, lastProcessTimestamp: {lastProcessTimestamp}");
@@ -94,11 +134,13 @@ private async Task InternalExposureDetectionAsync(CancellationTokenSource cancel
continue;
}
+ _loggerService.Info($"{targetDiagnosisKeyEntryList.Count()} new keys found.");
+
foreach (var diagnosisKeyEntry in targetDiagnosisKeyEntryList)
{
string filePath = await _diagnosisKeyRepository.DownloadDiagnosisKeysAsync(diagnosisKeyEntry, tmpDir, cancellationToken);
- _loggerService.Debug($"URL {diagnosisKeyEntry.Url} have been downloaded.");
+ _loggerService.Info($"URL {diagnosisKeyEntry.Url} have been downloaded.");
downloadedFileNameList.Add(filePath);
}
@@ -122,13 +164,14 @@ await _exposureNotificationApiService.ProvideDiagnosisKeysAsync(
}
catch (Exception exception)
{
- _userDataRepository.SetCanConfirmExposure(false);
+ canConfirmExposure = false;
_loggerService.Exception($"Exception occurred: {region}", exception);
throw;
}
finally
{
RemoveFiles(downloadedFileNameList);
+ _userDataRepository.SetCanConfirmExposure(canConfirmExposure);
}
}
}
@@ -171,6 +214,8 @@ private string PrepareDir(string region)
private void RemoveFiles(List fileList)
{
+ _loggerService.StartMethod();
+
foreach (var file in fileList)
{
try
@@ -182,6 +227,8 @@ private void RemoveFiles(List fileList)
_loggerService.Exception("Exception occurred", exception);
}
}
+
+ _loggerService.EndMethod();
}
}
}
diff --git a/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs b/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs
index 14f9a3b84..7b9846a37 100644
--- a/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs
+++ b/Covid19Radar/Covid19Radar/Services/DebugExposureDataCollectServer.cs
@@ -14,7 +14,7 @@
namespace Covid19Radar.Services
{
- public interface IExposureDataCollectServer
+ public interface IDebugExposureDataCollectServer
{
public Task UploadExposureDataAsync(
ExposureConfiguration exposureConfiguration,
@@ -39,7 +39,7 @@ string enVersion
);
}
- public class ReleaseExposureDataCollectServer : IExposureDataCollectServer
+ public class DebugExposureDataCollectServerNop : IDebugExposureDataCollectServer
{
public Task UploadExposureDataAsync(
ExposureConfiguration exposureConfiguration,
@@ -48,7 +48,7 @@ public Task UploadExposureDataAsync(
ExposureSummary exposureSummary,
IList exposureInformation
)
- => Task.FromResult(new List());
+ => Task.CompletedTask;
public Task UploadExposureDataAsync(
ExposureConfiguration exposureConfiguration,
@@ -57,18 +57,21 @@ public Task UploadExposureDataAsync(
IList dailySummaries,
IList exposureWindows
)
- => Task.FromResult(new List());
+ => Task.CompletedTask;
public Task UploadExposureDataAsync(
ExposureConfiguration exposureConfiguration,
string deviceModel,
string enVersion
)
- => Task.FromResult(new List());
+ => Task.CompletedTask;
}
+/// For user-privacy, this class is used for DEBUG only.
+/// Below #if is intented safe-guard for prevent contamination.
+/// DO NOT REMOVE.
#if DEBUG
- public class DebugExposureDataCollectServer : IExposureDataCollectServer
+ public class DebugExposureDataCollectServer : IDebugExposureDataCollectServer
{
private readonly ILoggerService _loggerService;
private readonly IServerConfigurationRepository _serverConfigurationRepository;
@@ -190,7 +193,6 @@ string exposureDataCollectServerEndpoint
}
}
}
-#endif
public class ExposureRequest
{
@@ -286,4 +288,5 @@ public class ExposureDataResponse
public readonly string? Uri;
}
+#endif
}
diff --git a/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs b/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs
index 33aa02e4f..9f52ad677 100644
--- a/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs
+++ b/Covid19Radar/Covid19Radar/Services/DiagnosisKeyRegisterServer.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
@@ -33,7 +32,7 @@ IDeviceVerifier deviceVerifier
_deviceVerifier = deviceVerifier;
}
- public async Task> SubmitDiagnosisKeysAsync(
+ public async Task SubmitDiagnosisKeysAsync(
DateTime symptomOnsetDate,
IList temporaryExposureKeys,
string processNumber,
@@ -62,9 +61,7 @@ string idempotencyKey
}
var diagnosisInfo = await CreateSubmissionAsync(symptomOnsetDate, temporaryExposureKeys, processNumber, idempotencyKey);
- IList httpStatusCode = await _httpDataService.PutSelfExposureKeysAsync(diagnosisInfo);
-
- return httpStatusCode;
+ return await _httpDataService.PutSelfExposureKeysAsync(diagnosisInfo);
}
finally
{
diff --git a/Covid19Radar/Covid19Radar/Services/DialogService.cs b/Covid19Radar/Covid19Radar/Services/DialogService.cs
index 35df8e7b7..2a782ab1f 100644
--- a/Covid19Radar/Covid19Radar/Services/DialogService.cs
+++ b/Covid19Radar/Covid19Radar/Services/DialogService.cs
@@ -55,6 +55,16 @@ public async Task ShowLocationOffWarningAsync()
AppResources.ButtonCancel);
}
+ public async Task ShowHomePageUnknownErrorWaringAsync()
+ {
+ await AlertAsync(
+ AppResources.HomePageDialogExceptionDescription,
+ AppResources.HomePageDialogExceptionTitle,
+ AppResources.ButtonOk);
+ }
+
+
+
public async Task ConfirmAsync(string message, string title = null, string okText = null, string cancelText = null) =>
await UserDialogs.Instance.ConfirmAsync(message, title, okText, cancelText);
diff --git a/Covid19Radar/Covid19Radar/Services/EventLogService.cs b/Covid19Radar/Covid19Radar/Services/EventLogService.cs
index 36655b1fe..6a00d6f28 100644
--- a/Covid19Radar/Covid19Radar/Services/EventLogService.cs
+++ b/Covid19Radar/Covid19Radar/Services/EventLogService.cs
@@ -44,6 +44,7 @@ string enVersion
);
}
+#if EVENT_LOG_ENABLED
public class EventLogService : IEventLogService
{
private readonly IUserDataRepository _userDataRepository;
@@ -142,11 +143,12 @@ ExposureData exposureData
{
_loggerService.StartMethod();
- bool hasConsent = _userDataRepository.IsSendEventLogEnabled();
+ SendEventLogState sendEventLogState = _userDataRepository.GetSendEventLogState();
+ bool isEnabled = sendEventLogState == SendEventLogState.Enable;
- if(!hasConsent)
+ if (!isEnabled)
{
- _loggerService.Debug($"No consent log.");
+ _loggerService.Debug($"Send event-log function is not enabled.");
_loggerService.EndMethod();
return;
}
@@ -161,7 +163,7 @@ ExposureData exposureData
var contentJson = exposureData.ToJsonString();
var eventLog = new V1EventLogRequest.EventLog() {
- HasConsent = hasConsent,
+ HasConsent = isEnabled,
Epoch = _dateTimeUtility.UtcNow.ToUnixEpoch(),
Type = "ExposureData",
Subtype = "Debug",
@@ -202,6 +204,7 @@ ExposureData exposureData
}
}
}
+#endif
public class ExposureData
{
diff --git a/Covid19Radar/Covid19Radar/Services/EventLogServiceNop.cs b/Covid19Radar/Covid19Radar/Services/EventLogServiceNop.cs
new file mode 100644
index 000000000..eccf1b9d7
--- /dev/null
+++ b/Covid19Radar/Covid19Radar/Services/EventLogServiceNop.cs
@@ -0,0 +1,47 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Chino;
+
+namespace Covid19Radar.Services
+{
+ public class EventLogServiceNop : IEventLogService
+ {
+ public Task SendExposureDataAsync(
+ string idempotencyKey,
+ ExposureConfiguration exposureConfiguration,
+ string deviceModel, string enVersion,
+ ExposureSummary exposureSummary,
+ IList exposureInformation
+ )
+ {
+ // do nothing
+ return Task.CompletedTask;
+ }
+
+ public Task SendExposureDataAsync(
+ string idempotencyKey,
+ ExposureConfiguration exposureConfiguration,
+ string deviceModel, string enVersion,
+ IList dailySummaries, IList exposureWindows
+ )
+ {
+ // do nothing
+ return Task.CompletedTask;
+ }
+
+ public Task SendExposureDataAsync(
+ string idempotencyKey,
+ ExposureConfiguration exposureConfiguration,
+ string deviceModel,
+ string enVersion
+ )
+ {
+ // do nothing
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/Covid19Radar/Covid19Radar/Services/ExposureDetectionService.cs b/Covid19Radar/Covid19Radar/Services/ExposureDetectionService.cs
index 2658a6b19..16bab8a5b 100644
--- a/Covid19Radar/Covid19Radar/Services/ExposureDetectionService.cs
+++ b/Covid19Radar/Covid19Radar/Services/ExposureDetectionService.cs
@@ -40,7 +40,7 @@ public class ExposureDetectionService : IExposureDetectionService
private readonly IEventLogService _eventLogService;
- private readonly IExposureDataCollectServer _exposureDataCollectServer;
+ private readonly IDebugExposureDataCollectServer _exposureDataCollectServer;
private readonly IDateTimeUtility _dateTimeUtility;
private readonly IDeviceInfoUtility _deviceInfoUtility;
@@ -54,7 +54,7 @@ public ExposureDetectionService
IExposureRiskCalculationService exposureRiskCalculationService,
IExposureConfigurationRepository exposureConfigurationRepository,
IEventLogService eventLogService,
- IExposureDataCollectServer exposureDataCollectServer,
+ IDebugExposureDataCollectServer exposureDataCollectServer,
IDateTimeUtility dateTimeUtility,
IDeviceInfoUtility deviceInfoUtility
)
@@ -108,6 +108,7 @@ public async Task ExposureDetectedAsync(ExposureConfiguration exposureConfigurat
var exposureRiskCalculationConfiguration = await _exposureRiskCalculationConfigurationRepository
.GetExposureRiskCalculationConfigurationAsync(preferCache: false);
+ _loggerService.Info(exposureRiskCalculationConfiguration.ToString());
bool isHighRiskExposureDetected = newDailySummaries
.Select(ds => _exposureRiskCalculationService.CalcRiskLevel(
diff --git a/Covid19Radar/Covid19Radar/Services/ExposureRiskCalculationService.cs b/Covid19Radar/Covid19Radar/Services/ExposureRiskCalculationService.cs
index 036745eb0..b089e6309 100644
--- a/Covid19Radar/Covid19Radar/Services/ExposureRiskCalculationService.cs
+++ b/Covid19Radar/Covid19Radar/Services/ExposureRiskCalculationService.cs
@@ -4,11 +4,11 @@
using System.Collections.Generic;
using System.Linq;
-using System.Threading.Tasks;
using Chino;
using Covid19Radar.Model;
using Covid19Radar.Services.Logs;
-using Newtonsoft.Json;
+
+using Threshold = Covid19Radar.Model.V1ExposureRiskCalculationConfiguration.Threshold;
namespace Covid19Radar.Services
{
@@ -39,7 +39,17 @@ public RiskLevel CalcRiskLevel(
V1ExposureRiskCalculationConfiguration configuration
)
{
- _ = LogAsync(configuration);
+ if (
+ configuration.DailySummary_DaySummary_ScoreSum.Op == Threshold.OPERATION_NOP
+ && configuration.DailySummary_WeightedDurationAverage.Op == Threshold.OPERATION_NOP
+ && configuration.ExposureWindow_ScanInstance_SecondsSinceLastScanSum.Op == Threshold.OPERATION_NOP
+ && configuration.ExposureWindow_ScanInstance_TypicalAttenuationDb_Max.Op == Threshold.OPERATION_NOP
+ && configuration.ExposureWindow_ScanInstance_TypicalAttenuationDb_Min.Op == Threshold.OPERATION_NOP
+ )
+ {
+ _loggerService.Info("All conditions are NOP.");
+ return RiskLevel.Low;
+ }
var allScanInstances = exposureWindowList
.SelectMany(ew => ew.ScanInstances);
@@ -65,34 +75,18 @@ V1ExposureRiskCalculationConfiguration configuration
typicalAttenuationDbMin = allScanInstances.Min(si => si.TypicalAttenuationDb);
}
- if (configuration.DailySummary_DaySummary_ScoreSum.Cond(dailySummary.DaySummary.ScoreSum))
- {
- return RiskLevel.High;
- }
- if (configuration.DailySummary_WeightedDurationAverage.Cond(weightedDurationAverage))
- {
- return RiskLevel.High;
- }
- if (configuration.ExposureWindow_ScanInstance_SecondsSinceLastScanSum.Cond(secondsSinceLastScanSum))
- {
- return RiskLevel.High;
- }
- if (configuration.ExposureWindow_ScanInstance_TypicalAttenuationDb_Max.Cond(typicalAttenuationDbMax))
- {
- return RiskLevel.High;
- }
- if (configuration.ExposureWindow_ScanInstance_TypicalAttenuationDb_Min.Cond(typicalAttenuationDbMin))
+ // AND
+ if (configuration.DailySummary_DaySummary_ScoreSum.Cond(dailySummary.DaySummary.ScoreSum)
+ && configuration.DailySummary_WeightedDurationAverage.Cond(weightedDurationAverage)
+ && configuration.ExposureWindow_ScanInstance_SecondsSinceLastScanSum.Cond(secondsSinceLastScanSum)
+ && configuration.ExposureWindow_ScanInstance_TypicalAttenuationDb_Max.Cond(typicalAttenuationDbMax)
+ && configuration.ExposureWindow_ScanInstance_TypicalAttenuationDb_Min.Cond(typicalAttenuationDbMin)
+ )
{
return RiskLevel.High;
}
return RiskLevel.Low;
}
-
- private async Task LogAsync(V1ExposureRiskCalculationConfiguration configuration)
- {
- string serializedJson = JsonConvert.SerializeObject(configuration);
- _loggerService.Info(serializedJson);
- }
}
}
diff --git a/Covid19Radar/Covid19Radar/Services/HttpDataService.cs b/Covid19Radar/Covid19Radar/Services/HttpDataService.cs
index fa782953c..e26404ab5 100644
--- a/Covid19Radar/Covid19Radar/Services/HttpDataService.cs
+++ b/Covid19Radar/Covid19Radar/Services/HttpDataService.cs
@@ -85,7 +85,7 @@ public async Task PostRegisterUserAsync()
return false;
}
- public async Task> PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request)
+ public async Task PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request)
{
loggerService.StartMethod();
@@ -94,13 +94,20 @@ public async Task> PutSelfExposureKeysAsync(DiagnosisSubmi
await serverConfigurationRepository.LoadAsync();
var diagnosisKeyRegisterApiUrls = serverConfigurationRepository.DiagnosisKeyRegisterApiUrls;
- var tasks = diagnosisKeyRegisterApiUrls.Select(async url =>
+ if (diagnosisKeyRegisterApiUrls.Count() == 0)
{
- var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
- return await PutAsync(url, content);
- });
+ loggerService.Error("DiagnosisKeyRegisterApiUrls count 0");
+ throw new InvalidOperationException("DiagnosisKeyRegisterApiUrls count 0");
+ }
+ else if (diagnosisKeyRegisterApiUrls.Count() > 1)
+ {
+ loggerService.Warning("Multi DiagnosisKeyRegisterApiUrl are detected.");
+ }
+
+ var url = diagnosisKeyRegisterApiUrls.First();
+ var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
- return await Task.WhenAll(tasks);
+ return await PutAsync(url, content);
}
finally
{
diff --git a/Covid19Radar/Covid19Radar/Services/HttpDataServiceMock.cs b/Covid19Radar/Covid19Radar/Services/HttpDataServiceMock.cs
index cbf6da08c..287fea66b 100644
--- a/Covid19Radar/Covid19Radar/Services/HttpDataServiceMock.cs
+++ b/Covid19Radar/Covid19Radar/Services/HttpDataServiceMock.cs
@@ -105,7 +105,7 @@ async Task IHttpDataService.PostRegisterUserAsync()
return await Task.FromResult(result);
}
- Task> IHttpDataService.PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request)
+ Task IHttpDataService.PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request)
{
var code = HttpStatusCode.OK; // default. for PutSelfExposureKeys NG
var dataType = mockCommonUtils.GetDiagnosisDataType();
@@ -122,11 +122,9 @@ Task> IHttpDataService.PutSelfExposureKeysAsync(DiagnosisS
break;
}
}
- return Task.Factory.StartNew>(() =>
- {
- Debug.WriteLine("HttpDataServiceMock::PutSelfExposureKeysAsync called");
- return new List() { code };
- });
+
+ Debug.WriteLine("HttpDataServiceMock::PutSelfExposureKeysAsync called");
+ return Task.FromResult(code);
}
public Task> GetLogStorageSas()
diff --git a/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs b/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs
index 0dbe4f498..c398fa465 100644
--- a/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs
+++ b/Covid19Radar/Covid19Radar/Services/IDiagnosisKeyRegisterServer.cs
@@ -12,7 +12,7 @@ namespace Covid19Radar.Services
{
public interface IDiagnosisKeyRegisterServer
{
- public Task> SubmitDiagnosisKeysAsync(
+ public Task SubmitDiagnosisKeysAsync(
DateTime symptomOnsetDate,
IList temporaryExposureKeys,
string processNumber,
diff --git a/Covid19Radar/Covid19Radar/Services/IDialogService.cs b/Covid19Radar/Covid19Radar/Services/IDialogService.cs
index e670e184b..bb685b052 100644
--- a/Covid19Radar/Covid19Radar/Services/IDialogService.cs
+++ b/Covid19Radar/Covid19Radar/Services/IDialogService.cs
@@ -11,5 +11,6 @@ public interface IDialogService
Task ShowExposureNotificationOffWarningAsync();
Task ShowBluetoothOffWarningAsync();
Task ShowLocationOffWarningAsync();
+ Task ShowHomePageUnknownErrorWaringAsync();
}
}
diff --git a/Covid19Radar/Covid19Radar/Services/IHttpDataService.cs b/Covid19Radar/Covid19Radar/Services/IHttpDataService.cs
index b6f63e6c6..9d312d61c 100644
--- a/Covid19Radar/Covid19Radar/Services/IHttpDataService.cs
+++ b/Covid19Radar/Covid19Radar/Services/IHttpDataService.cs
@@ -3,7 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using Covid19Radar.Model;
-using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
@@ -13,7 +12,7 @@ public interface IHttpDataService
{
Task PostRegisterUserAsync();
- Task> PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request);
+ Task PutSelfExposureKeysAsync(DiagnosisSubmissionParameter request);
Task> GetLogStorageSas();
}
diff --git a/Covid19Radar/Covid19Radar/Services/Migration/MigrationService.cs b/Covid19Radar/Covid19Radar/Services/Migration/MigrationService.cs
index be1578ba1..25de891cc 100644
--- a/Covid19Radar/Covid19Radar/Services/Migration/MigrationService.cs
+++ b/Covid19Radar/Covid19Radar/Services/Migration/MigrationService.cs
@@ -61,7 +61,7 @@ private void SetPreferenceVersion(Version version)
if (!_preferencesService.ContainsKey(PreferenceKey.AppVersion))
{
- _loggerService.Debug($"appVersion entry is not found in Preferences.");
+ _loggerService.Info($"appVersion entry is not found in Preferences.");
_loggerService.EndMethod();
return null;
}
@@ -188,7 +188,7 @@ private async Task MigrateAsync(Version? fromVersion)
if (fromVersion.CompareTo(GetCurrentAppVersion()) == 0)
{
- _loggerService.Debug($"fromVersion: {fromVersion} == currentVersion: {GetCurrentAppVersion()}");
+ _loggerService.Info($"fromVersion: {fromVersion} == currentVersion: {GetCurrentAppVersion()}");
_loggerService.EndMethod();
return;
}
diff --git a/Covid19Radar/Covid19Radar/ViewModels/ExceptionPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/ExceptionPageViewModel.cs
deleted file mode 100644
index 7a50b3562..000000000
--- a/Covid19Radar/Covid19Radar/ViewModels/ExceptionPageViewModel.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-using Prism.Mvvm;
-
-namespace Covid19Radar.ViewModels
-{
- public class ExceptionPageViewModel : BindableBase
- {
- private string _message;
- public string Message
- {
- get => _message;
- set => SetProperty(ref _message, value);
- }
- }
-}
diff --git a/Covid19Radar/Covid19Radar/ViewModels/ExposureCheck/ExposureCheckPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/ExposureCheck/ExposureCheckPageViewModel.cs
index ab2305493..0753bf369 100644
--- a/Covid19Radar/Covid19Radar/ViewModels/ExposureCheck/ExposureCheckPageViewModel.cs
+++ b/Covid19Radar/Covid19Radar/ViewModels/ExposureCheck/ExposureCheckPageViewModel.cs
@@ -13,14 +13,21 @@
using System.Collections.Generic;
using System;
using Xamarin.Forms;
+using Covid19Radar.Views;
+using Covid19Radar.Resources;
+
+using Threshold = Covid19Radar.Model.V1ExposureRiskCalculationConfiguration.Threshold;
+using Covid19Radar.Services;
+using System.Threading.Tasks;
+using System.Globalization;
namespace Covid19Radar.ViewModels
{
public class ExposureCheckPageViewModel : ViewModelBase
{
private readonly ILoggerService _loggerService;
- private readonly IUserDataRepository _userDataRepository;
private readonly IExposureDataRepository _exposureDataRepository;
+ private readonly IExposureRiskCalculationService _exposureRiskCalculationService;
public ObservableCollection ExposureCheckScores { get; set; }
@@ -38,16 +45,32 @@ public bool IsVisibleLowRiskContact
set { SetProperty(ref _isVisibleLowRiskContact, value); }
}
+ private string _lowRiskContactPageHeaderTextSuffix;
+ public string LowRiskContactPageHeaderTextSuffix
+ {
+ get { return _lowRiskContactPageHeaderTextSuffix; }
+ set { SetProperty(ref _lowRiskContactPageHeaderTextSuffix, value); }
+ }
+
+ private string _lowRiskContactPageAnnotationDecription;
+ public string LowRiskContactPageAnnotationDecription
+ {
+ get { return _lowRiskContactPageAnnotationDecription; }
+ set { SetProperty(ref _lowRiskContactPageAnnotationDecription, value); }
+ }
+
+ private V1ExposureRiskCalculationConfiguration _exposureRiskCalculationConfiguration;
+
public ExposureCheckPageViewModel(
INavigationService navigationService,
ILoggerService loggerService,
- IUserDataRepository userDataRepository,
- IExposureDataRepository exposureDataRepository
+ IExposureDataRepository exposureDataRepository,
+ IExposureRiskCalculationService exposureRiskCalculationService
) : base(navigationService)
{
- this._loggerService = loggerService;
- this._userDataRepository = userDataRepository;
+ _loggerService = loggerService;
_exposureDataRepository = exposureDataRepository;
+ _exposureRiskCalculationService = exposureRiskCalculationService;
ExposureCheckScores = new ObservableCollection();
}
@@ -58,6 +81,11 @@ public override async void Initialize(INavigationParameters parameters)
_loggerService.StartMethod();
+ _exposureRiskCalculationConfiguration
+ = parameters.GetValue(ExposureCheckPage.ExposureRiskCalculationConfigurationKey);
+
+ ShowExposureRiskCalculationConfiguration();
+
try
{
var summaries = await _exposureDataRepository
@@ -67,7 +95,7 @@ public override async void Initialize(INavigationParameters parameters)
IsVisibleLowRiskContact = true;
IsVisibleNoRiskContact = false;
- SetupExposureCheckScores(summaries);
+ _ = SetupExposureCheckScoresAsync(summaries);
}
else
{
@@ -85,19 +113,136 @@ public override async void Initialize(INavigationParameters parameters)
}
}
- private void SetupExposureCheckScores(List summaries)
+ private void ShowExposureRiskCalculationConfiguration()
{
- summaries.Sort((a, b) => b.GetDateTime().CompareTo(a.GetDateTime()));
+ if (_exposureRiskCalculationConfiguration.DailySummary_DaySummary_ScoreSum.Op
+ == Threshold.OPERATION_NOP)
+ {
+ _loggerService.Info("_exposureRiskCalculationConfiguration.DailySummary_DaySummary_ScoreSum.Op = NOP");
+ return;
+ }
- foreach (var summary in summaries)
+ LowRiskContactPageAnnotationDecription
+ = string.Format(
+ AppResources.LowRiskContactPageAnnotationDecription,
+ _exposureRiskCalculationConfiguration.DailySummary_DaySummary_ScoreSum.Value,
+ OperatorToString(_exposureRiskCalculationConfiguration.DailySummary_DaySummary_ScoreSum.Op)
+ );
+ }
+
+ private static string OperatorToString(string op)
+ {
+ return op switch
{
- ExposureCheckScores.Add(
- new ExposureCheckScoreModel()
- {
- DailySummaryScoreSum = summary.DaySummary.ScoreSum,
- DateMillisSinceEpoch = summary.DateMillisSinceEpoch
- });
+ Threshold.OPERATION_GREATER_EQUAL => AppResources.ThresholdTextOperatorGte,
+ Threshold.OPERATION_GREATER => AppResources.ThresholdTextOperatorGt,
+ Threshold.OPERATION_EQUAL => AppResources.ThresholdTextOperatorEqual,
+ Threshold.OPERATION_LESS => AppResources.ThresholdTextOperatorLt,
+ Threshold.OPERATION_LESS_EQUAL => AppResources.ThresholdTextOperatorLte,
+ Threshold.OPERATION_NOP => string.Empty,
+ _ => string.Empty
+ };
+ }
+
+ private async Task SetupExposureCheckScoresAsync(List summaries)
+ {
+ var dailySummaryList
+ = await _exposureDataRepository.GetDailySummariesAsync(AppConstants.DaysOfExposureInformationToDisplay);
+
+ if (dailySummaryList.Count() == 0)
+ {
+ return;
}
+
+ _loggerService.Info(_exposureRiskCalculationConfiguration.ToString());
+
+ var dailySummaryMap = dailySummaryList.ToDictionary(ds => ds.GetDateTime());
+
+ var exposureWindowList
+ = await _exposureDataRepository.GetExposureWindowsAsync(AppConstants.DaysOfExposureInformationToDisplay);
+ exposureWindowList.Sort((a, b) => b.DateMillisSinceEpoch.CompareTo(a.DateMillisSinceEpoch));
+
+ var userExposureInformationList
+ = _exposureDataRepository.GetExposureInformationList(AppConstants.DaysOfExposureInformationToDisplay);
+
+ foreach (var ew in exposureWindowList.GroupBy(exposureWindow => exposureWindow.GetDateTime()))
+ {
+ if (!dailySummaryMap.ContainsKey(ew.Key))
+ {
+ _loggerService.Warning($"ExposureWindow: {ew.Key} found, but that is not contained the list of dailySummary.");
+ continue;
+ }
+
+ var dailySummary = dailySummaryMap[ew.Key];
+
+ RiskLevel riskLevel = _exposureRiskCalculationService.CalcRiskLevel(
+ dailySummary,
+ ew.ToList(),
+ _exposureRiskCalculationConfiguration
+ );
+ if (riskLevel > RiskLevel.Low)
+ {
+ continue;
+ }
+
+ ExposureCheckScoreModel exposureCheckModel = CreateExposureCheckScoreModel(dailySummary, ew.ToList());
+ ExposureCheckScores.Add(exposureCheckModel);
+ }
+ }
+
+ private ExposureCheckScoreModel CreateExposureCheckScoreModel(DailySummary dailySummary, List exposureWindowList)
+ {
+ var exposureCheckModel = new ExposureCheckScoreModel()
+ {
+ DateMillisSinceEpoch = dailySummary.DateMillisSinceEpoch,
+ };
+
+ var descriptionList = new List();
+
+ if (!_exposureRiskCalculationConfiguration.DailySummary_DaySummary_ScoreSum.Cond(dailySummary.DaySummary.ScoreSum))
+ {
+ exposureCheckModel.IsScoreVisible = true;
+
+ var description = string.Format(
+ AppResources.LowRiskContactPage_DailySummary_ScoreSum_Descritpion_Unsatisfied,
+ dailySummary.DaySummary.ScoreSum
+ );
+ descriptionList.Add(description);
+ }
+ else
+ {
+ var description = string.Format(
+ AppResources.LowRiskContactPage_DailySummary_ScoreSum_Descritpion_Satisfied,
+ dailySummary.DaySummary.ScoreSum
+ );
+ descriptionList.Add(description);
+ }
+
+ var exposureDurationInSec = exposureWindowList.Sum(e => e.ScanInstances.Sum(s => s.SecondsSinceLastScan));
+
+ if (!exposureCheckModel.IsScoreVisible
+ && !_exposureRiskCalculationConfiguration.ExposureWindow_ScanInstance_SecondsSinceLastScanSum.Cond(exposureDurationInSec))
+ {
+ exposureCheckModel.IsDurationTimeVisible = true;
+
+ var exposureDurationTimeSpan = TimeSpan.FromSeconds(exposureDurationInSec);
+ var exposureDurationInMinute = Math.Ceiling(exposureDurationTimeSpan.TotalMinutes);
+
+ var exposureDurationThresholdTimeSpan = TimeSpan.FromSeconds(_exposureRiskCalculationConfiguration.ExposureWindow_ScanInstance_SecondsSinceLastScanSum.Value);
+ var exposureDurationThresholdInMinute = Math.Ceiling(exposureDurationThresholdTimeSpan.TotalMinutes);
+
+ var description = string.Format(
+ AppResources.LowRiskContactPage_ExposureDuration_Description_Unsatisfied,
+ exposureDurationInMinute
+ );
+ descriptionList.Add(description);
+ }
+
+ // Score is always visible
+ exposureCheckModel.IsScoreVisible = true;
+ exposureCheckModel.Description = string.Join("\n", descriptionList);
+
+ return exposureCheckModel;
}
public Command OnClickShareApp => new Command(() =>
@@ -109,4 +254,19 @@ private void SetupExposureCheckScores(List summaries)
_loggerService.EndMethod();
});
}
+
+ public class ExposureCheckScoreModel
+ {
+ public long DateMillisSinceEpoch { get; set; }
+
+ public string DateTimeString => DateTimeOffset.UnixEpoch
+ .AddMilliseconds(DateMillisSinceEpoch).UtcDateTime
+ .ToLocalTime().ToString("D", CultureInfo.CurrentCulture);
+
+ public bool IsScoreVisible { get; set; }
+
+ public bool IsDurationTimeVisible { get; set; }
+
+ public string Description { get; set; }
+ }
}
\ No newline at end of file
diff --git a/Covid19Radar/Covid19Radar/ViewModels/HelpPage/InqueryPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HelpPage/InqueryPageViewModel.cs
index 5aedc2ef3..6430a01f6 100644
--- a/Covid19Radar/Covid19Radar/ViewModels/HelpPage/InqueryPageViewModel.cs
+++ b/Covid19Radar/Covid19Radar/ViewModels/HelpPage/InqueryPageViewModel.cs
@@ -21,7 +21,7 @@ public class InqueryPageViewModel : ViewModelBase
private readonly ILogFileService logFileService;
private readonly ILogPathService logPathService;
- private readonly IEssentialsService essentialService;
+ private readonly IEssentialsService essentialsService;
public Func BrowserOpenAsync = Browser.OpenAsync;
public Func ComposeEmailAsync { get; set; } = Email.ComposeAsync;
@@ -31,14 +31,14 @@ public InqueryPageViewModel(
ILoggerService loggerService,
ILogFileService logFileService,
ILogPathService logPathService,
- IEssentialsService eseentialService
+ IEssentialsService essentialsService
) : base(navigationService)
{
Title = AppResources.InqueryPageTitle;
this.loggerService = loggerService;
this.logFileService = logFileService;
this.logPathService = logPathService;
- this.essentialService = eseentialService;
+ this.essentialsService = essentialsService;
}
public Command OnClickQuestionCommand => new Command(async () =>
@@ -137,7 +137,7 @@ await Share.RequestAsync(new ShareFileRequest
{
await ComposeEmailAsync(
AppResources.InquiryMailSubject,
- AppResources.InquiryMailBody.Replace("\\r\\n", "\r\n"),
+ CreateInquiryMailBody(),
new string[] { AppSettings.Instance.SupportEmail });
loggerService.EndMethod();
@@ -159,6 +159,15 @@ await ComposeEmailAsync(
loggerService.EndMethod();
});
+ private string CreateInquiryMailBody()
+ {
+ return AppResources.InquiryMailBody.Replace("\\r\\n", "\r\n")
+ + AppResources.InquiryMailModelTitle + essentialsService.Model + "\r\n"
+ + AppResources.InquiryMailOSTitle + essentialsService.Platform + "\r\n"
+ + AppResources.InquiryMailOSVersionTitle + essentialsService.PlatformVersion + "\r\n"
+ + AppResources.InquiryMailAppVersionTitle + essentialsService.AppVersion;
+ }
+
private (string, string) CreateZipFile()
{
string logId = logFileService.CreateLogId();
diff --git a/Covid19Radar/Covid19Radar/ViewModels/HomePage/ContactedNotifyPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HomePage/ContactedNotifyPageViewModel.cs
index 913272f69..b49b1d176 100644
--- a/Covid19Radar/Covid19Radar/ViewModels/HomePage/ContactedNotifyPageViewModel.cs
+++ b/Covid19Radar/Covid19Radar/ViewModels/HomePage/ContactedNotifyPageViewModel.cs
@@ -43,8 +43,7 @@ public ContactedNotifyPageViewModel(
ILoggerService loggerService,
IExposureDataRepository exposureDataRepository,
IExposureRiskCalculationService exposureRiskCalculationService,
- IExposureRiskCalculationConfigurationRepository exposureRiskCalculationConfigurationRepository
- ) : base(navigationService)
+ IExposureRiskCalculationConfigurationRepository exposureRiskCalculationConfigurationRepository) : base(navigationService)
{
this.loggerService = loggerService;
_exposureDataRepository = exposureDataRepository;
@@ -58,64 +57,84 @@ public override async void Initialize(INavigationParameters parameters)
{
base.Initialize(parameters);
- var exposureRiskCalculationConfiguration
- = await _exposureRiskCalculationConfigurationRepository.GetExposureRiskCalculationConfigurationAsync(preferCache: false);
+ try
+ {
+ loggerService.StartMethod();
- var userExposureInformationList = _exposureDataRepository.GetExposureInformationList(AppConstants.DaysOfExposureInformationToDisplay);
+ var exposureRiskCalculationConfiguration
+ = await _exposureRiskCalculationConfigurationRepository.GetExposureRiskCalculationConfigurationAsync(preferCache: true);
+ loggerService.Info(exposureRiskCalculationConfiguration.ToString());
- string contactedNotifyPageCountFormat = AppResources.ContactedNotifyPageCountOneText;
- if (userExposureInformationList.Count() > 1)
- {
- contactedNotifyPageCountFormat = AppResources.ContactedNotifyPageCountText;
- }
+ var userExposureInformationList = _exposureDataRepository.GetExposureInformationList(AppConstants.DaysOfExposureInformationToDisplay);
- var dailySummaryList = await _exposureDataRepository.GetDailySummariesAsync(AppConstants.DaysOfExposureInformationToDisplay);
- var dailySummaryMap = dailySummaryList.ToDictionary(ds => ds.GetDateTime());
- var exposureWindowList = await _exposureDataRepository.GetExposureWindowsAsync(AppConstants.DaysOfExposureInformationToDisplay);
+ string contactedNotifyPageCountFormat = AppResources.ContactedNotifyPageCountOneText;
+ if (userExposureInformationList.Count() > 1)
+ {
+ contactedNotifyPageCountFormat = AppResources.ContactedNotifyPageCountText;
+ }
- int dayCount = 0;
- long exposureDurationInSec = 0;
- foreach (var ew in exposureWindowList.GroupBy(exposureWindow => exposureWindow.GetDateTime()))
- {
- var dailySummary = dailySummaryMap[ew.Key];
+ var dailySummaryList = await _exposureDataRepository.GetDailySummariesAsync(AppConstants.DaysOfExposureInformationToDisplay);
+ var dailySummaryMap = dailySummaryList.ToDictionary(ds => ds.GetDateTime());
+ var exposureWindowList = await _exposureDataRepository.GetExposureWindowsAsync(AppConstants.DaysOfExposureInformationToDisplay);
- RiskLevel riskLevel = _exposureRiskCalculationService.CalcRiskLevel(dailySummary, ew.ToList(), exposureRiskCalculationConfiguration);
- if (riskLevel >= RiskLevel.High)
+ int dayCount = 0;
+ long exposureDurationInSec = 0;
+ foreach (var ew in exposureWindowList.GroupBy(exposureWindow => exposureWindow.GetDateTime()))
{
- exposureDurationInSec += ew.Sum(e => e.ScanInstances.Sum(s => s.SecondsSinceLastScan));
- dayCount += 1;
+ if (!dailySummaryMap.ContainsKey(ew.Key))
+ {
+ loggerService.Warning($"ExposureWindow: {ew.Key} found, but that is not contained the list of dailySummary.");
+ continue;
+ }
+
+ var dailySummary = dailySummaryMap[ew.Key];
+
+ RiskLevel riskLevel = _exposureRiskCalculationService.CalcRiskLevel(dailySummary, ew.ToList(), exposureRiskCalculationConfiguration);
+ if (riskLevel >= RiskLevel.High)
+ {
+ exposureDurationInSec += ew.Sum(e => e.ScanInstances.Sum(s => s.SecondsSinceLastScan));
+ dayCount += 1;
+ }
}
- }
- string contactedNotifyPageExposureDurationFormat = AppResources.ContactedNotifyPageExposureDurationOne;
- if (dayCount > 1)
- {
- contactedNotifyPageExposureDurationFormat = AppResources.ContactedNotifyPageExposureDuration;
- }
- TimeSpan timeSpan = TimeSpan.FromSeconds(exposureDurationInSec);
- var totalMinutes = Math.Ceiling(timeSpan.TotalMinutes);
+ string contactedNotifyPageExposureDurationFormat = AppResources.ContactedNotifyPageExposureDurationOne;
+ if (dayCount > 1)
+ {
+ contactedNotifyPageExposureDurationFormat = AppResources.ContactedNotifyPageExposureDuration;
+ }
+ TimeSpan timeSpan = TimeSpan.FromSeconds(exposureDurationInSec);
+ var totalMinutes = Math.Ceiling(timeSpan.TotalMinutes);
- if (userExposureInformationList.Count() > 0 && dayCount > 0)
- {
- // Show Headers
- var beforeDateMillisSinceEpoch = userExposureInformationList.Max(ei => ei.Timestamp.ToUnixEpochMillis());
- var afterDateMillisSinceEpoch = dailySummaryList.Min(ds => ds.DateMillisSinceEpoch);
+ if (userExposureInformationList.Count() > 0 && dayCount > 0)
+ {
+ // Show Headers
+ var beforeDateMillisSinceEpoch = userExposureInformationList.Max(ei => ei.Timestamp.ToUnixEpochMillis());
+ var afterDateMillisSinceEpoch = dailySummaryList.Min(ds => ds.DateMillisSinceEpoch);
- var beforeDate = DateTimeOffset.UnixEpoch.AddMilliseconds(beforeDateMillisSinceEpoch).UtcDateTime;
- var afterDate = DateTimeOffset.UnixEpoch.AddMilliseconds(afterDateMillisSinceEpoch).UtcDateTime;
+ var beforeDate = DateTimeOffset.UnixEpoch.AddMilliseconds(beforeDateMillisSinceEpoch).UtcDateTime;
+ var afterDate = DateTimeOffset.UnixEpoch.AddMilliseconds(afterDateMillisSinceEpoch).UtcDateTime;
- ExposureCount = string.Format(AppResources.ContactedNotifyPageCountHeader, beforeDate.ToString("D")) + "\n"
- + string.Format(contactedNotifyPageCountFormat, userExposureInformationList.Count());
- ExposureDurationInMinutes = string.Format(AppResources.ContactedNotifyPageExposureDurationHeader, afterDate.ToString("D")) + "\n"
- + string.Format(contactedNotifyPageExposureDurationFormat, dayCount, totalMinutes);
+ ExposureCount = string.Format(AppResources.ContactedNotifyPageCountHeader, beforeDate.ToString("D")) + "\n"
+ + string.Format(contactedNotifyPageCountFormat, userExposureInformationList.Count());
+ ExposureDurationInMinutes = string.Format(AppResources.ContactedNotifyPageExposureDurationHeader, afterDate.ToString("D")) + "\n"
+ + string.Format(contactedNotifyPageExposureDurationFormat, dayCount, totalMinutes);
+ }
+ else if (exposureDurationInSec > 0)
+ {
+ ExposureDurationInMinutes = string.Format(contactedNotifyPageExposureDurationFormat, dayCount, totalMinutes);
+ }
+ else if (userExposureInformationList.Count() > 0)
+ {
+ ExposureCount = string.Format(contactedNotifyPageCountFormat, userExposureInformationList.Count());
+ }
}
- else if (exposureDurationInSec > 0)
+ catch(Exception exception)
{
- ExposureDurationInMinutes = string.Format(contactedNotifyPageExposureDurationFormat, dayCount, totalMinutes);
+ loggerService.Exception("Failed to Initialize", exception);
}
- else if (userExposureInformationList.Count() > 0)
+ finally
{
- ExposureCount = string.Format(contactedNotifyPageCountFormat, userExposureInformationList.Count());
+ loggerService.EndMethod();
}
}
diff --git a/Covid19Radar/Covid19Radar/ViewModels/HomePage/ExposuresPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HomePage/ExposuresPageViewModel.cs
index f1e2f5dc6..d1b9e70c8 100644
--- a/Covid19Radar/Covid19Radar/ViewModels/HomePage/ExposuresPageViewModel.cs
+++ b/Covid19Radar/Covid19Radar/ViewModels/HomePage/ExposuresPageViewModel.cs
@@ -7,6 +7,7 @@
using Covid19Radar.Repository;
using Covid19Radar.Resources;
using Covid19Radar.Services;
+using Covid19Radar.Services.Logs;
using Prism.Navigation;
using System;
using System.Collections.ObjectModel;
@@ -21,29 +22,25 @@ public class ExposuresPageViewModel : ViewModelBase
private readonly IExposureDataRepository _exposureDataRepository;
private readonly IExposureRiskCalculationConfigurationRepository _exposureRiskCalculationConfigurationRepository;
private readonly IExposureRiskCalculationService _exposureRiskCalculationService;
+ private readonly ILoggerService _loggerService;
- public ObservableCollection _exposures;
-
- public ObservableCollection Exposures
- {
- get { return _exposures; }
- set { SetProperty(ref _exposures, value); }
- }
+ public ObservableCollection Exposures { get; set; }
public ExposuresPageViewModel(
INavigationService navigationService,
IExposureDataRepository exposureDataRepository,
IExposureRiskCalculationConfigurationRepository exposureRiskCalculationConfigurationRepository,
- IExposureRiskCalculationService exposureRiskCalculationService
+ IExposureRiskCalculationService exposureRiskCalculationService,
+ ILoggerService loggerService
) : base(navigationService)
{
_exposureDataRepository = exposureDataRepository;
_exposureRiskCalculationConfigurationRepository = exposureRiskCalculationConfigurationRepository;
_exposureRiskCalculationService = exposureRiskCalculationService;
+ _loggerService = loggerService;
Title = AppResources.MainExposures;
- _exposures = new ObservableCollection();
-
+ Exposures = new ObservableCollection();
}
public override async void Initialize(INavigationParameters parameters)
@@ -55,8 +52,11 @@ public override async void Initialize(INavigationParameters parameters)
public async Task InitExposures()
{
+ var exposures = new ObservableCollection();
+
var exposureRiskCalculationConfiguration
= await _exposureRiskCalculationConfigurationRepository.GetExposureRiskCalculationConfigurationAsync(preferCache: false);
+ _loggerService.Info(exposureRiskCalculationConfiguration.ToString());
var dailySummaryList
= await _exposureDataRepository.GetDailySummariesAsync(AppConstants.DaysOfExposureInformationToDisplay);
@@ -72,6 +72,12 @@ var userExposureInformationList
{
foreach (var ew in exposureWindowList.GroupBy(exposureWindow => exposureWindow.GetDateTime()))
{
+ if (!dailySummaryMap.ContainsKey(ew.Key))
+ {
+ _loggerService.Warning($"ExposureWindow: {ew.Key} found, but that is not contained the list of dailySummary.");
+ continue;
+ }
+
var dailySummary = dailySummaryMap[ew.Key];
RiskLevel riskLevel = _exposureRiskCalculationService.CalcRiskLevel(
@@ -92,7 +98,7 @@ var userExposureInformationList
var exposureDurationInSec = ew.Sum(e => e.ScanInstances.Sum(s => s.SecondsSinceLastScan));
ens.SetExposureTime(exposureDurationInSec);
- _exposures.Add(ens);
+ exposures.Add(ens);
}
}
@@ -106,13 +112,15 @@ var userExposureInformationList
ExposureDate = ei.Key.ToLocalTime().ToString("D", CultureInfo.CurrentCulture),
};
ens.SetExposureCount(ei.Count());
- _exposures.Add(ens);
+ exposures.Add(ens);
}
}
- Exposures = new ObservableCollection(
- _exposures.OrderByDescending(exposureSummary => exposureSummary.Timestamp)
- );
+ Exposures.Clear();
+ foreach (var exposure in exposures.OrderByDescending(exposureSummary => exposureSummary.Timestamp))
+ {
+ Exposures.Add(exposure);
+ }
}
}
diff --git a/Covid19Radar/Covid19Radar/ViewModels/HomePage/HomePageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HomePage/HomePageViewModel.cs
index 2280bb115..1893b236c 100644
--- a/Covid19Radar/Covid19Radar/ViewModels/HomePage/HomePageViewModel.cs
+++ b/Covid19Radar/Covid19Radar/ViewModels/HomePage/HomePageViewModel.cs
@@ -127,7 +127,16 @@ public override async void Initialize(INavigationParameters parameters)
await StartExposureNotificationAsync();
- _ = exposureDetectionBackgroundService.ExposureDetectionAsync();
+ _ = Task.Run(async () => {
+ try
+ {
+ await exposureDetectionBackgroundService.ExposureDetectionAsync();
+ }
+ finally
+ {
+ await UpdateView();
+ }
+ });
loggerService.EndMethod();
}
@@ -158,49 +167,73 @@ private async Task StartExposureNotificationAsync()
public Command OnClickExposures => new Command(async () =>
{
- loggerService.StartMethod();
+ try
+ {
+ UserDialogs.Instance.ShowLoading(AppResources.Loading);
+ loggerService.StartMethod();
- var exposureRiskCalculationConfiguration = await exposureRiskCalculationConfigurationRepository
- .GetExposureRiskCalculationConfigurationAsync(preferCache: true);
+ var exposureRiskCalculationConfiguration = await exposureRiskCalculationConfigurationRepository
+ .GetExposureRiskCalculationConfigurationAsync(preferCache: true);
+ loggerService.Info(exposureRiskCalculationConfiguration.ToString());
- var dailySummaryList = await _exposureDataRepository.GetDailySummariesAsync(AppConstants.DaysOfExposureInformationToDisplay);
- var dailySummaryMap = dailySummaryList.ToDictionary(ds => ds.GetDateTime());
- var exposureWindowList = await _exposureDataRepository.GetExposureWindowsAsync(AppConstants.DaysOfExposureInformationToDisplay);
+ var dailySummaryList = await _exposureDataRepository.GetDailySummariesAsync(AppConstants.DaysOfExposureInformationToDisplay);
+ var dailySummaryMap = dailySummaryList.ToDictionary(ds => ds.GetDateTime());
+ var exposureWindowList = await _exposureDataRepository.GetExposureWindowsAsync(AppConstants.DaysOfExposureInformationToDisplay);
- var userExposureInformationList = _exposureDataRepository.GetExposureInformationList(AppConstants.DaysOfExposureInformationToDisplay);
+ var userExposureInformationList = _exposureDataRepository.GetExposureInformationList(AppConstants.DaysOfExposureInformationToDisplay);
- var hasExposure = dailySummaryList.Count() > 0 || userExposureInformationList.Count() > 0;
- var hasHighRiskExposure = userExposureInformationList.Count() > 0;
+ var hasExposure = dailySummaryList.Count() > 0 || userExposureInformationList.Count() > 0;
+ var hasHighRiskExposure = userExposureInformationList.Count() > 0;
- foreach (var ew in exposureWindowList.GroupBy(exposureWindow => exposureWindow.GetDateTime()))
- {
- var dailySummary = dailySummaryMap[ew.Key];
- RiskLevel riskLevel = _exposureRiskCalculationService.CalcRiskLevel(
- dailySummary,
- ew.ToList(),
- exposureRiskCalculationConfiguration
- );
- if (riskLevel >= RiskLevel.High)
+ foreach (var ew in exposureWindowList.GroupBy(exposureWindow => exposureWindow.GetDateTime()))
{
- hasHighRiskExposure = true;
- break;
+ if (!dailySummaryMap.ContainsKey(ew.Key))
+ {
+ loggerService.Warning($"ExposureWindow: {ew.Key} found, but that is not contained the list of dailySummary.");
+ continue;
+ }
+
+ var dailySummary = dailySummaryMap[ew.Key];
+ RiskLevel riskLevel = _exposureRiskCalculationService.CalcRiskLevel(
+ dailySummary,
+ ew.ToList(),
+ exposureRiskCalculationConfiguration
+ );
+ if (riskLevel >= RiskLevel.High)
+ {
+ hasHighRiskExposure = true;
+ break;
+ }
}
- }
- await localNotificationService.DismissExposureNotificationAsync();
+ await localNotificationService.DismissExposureNotificationAsync();
+
+ UserDialogs.Instance.HideLoading();
- if (hasHighRiskExposure)
+ if (hasHighRiskExposure)
+ {
+ await NavigationService.NavigateAsync(nameof(ContactedNotifyPage));
+ return;
+ }
+ else
+ {
+ INavigationParameters navigaitonParameters
+ = ExposureCheckPage.BuildNavigationParams(exposureRiskCalculationConfiguration);
+ await NavigationService.NavigateAsync(nameof(ExposureCheckPage), navigaitonParameters);
+ return;
+ }
+ }
+ catch (Exception exception)
{
- await NavigationService.NavigateAsync(nameof(ContactedNotifyPage));
- loggerService.EndMethod();
- return;
+ UserDialogs.Instance.HideLoading();
+ loggerService.Exception("Failed to Initialize", exception);
+ await dialogService.ShowHomePageUnknownErrorWaringAsync();
}
- else
+ finally
{
- await NavigationService.NavigateAsync(nameof(ExposureCheckPage));
loggerService.EndMethod();
- return;
}
+
});
public Command OnClickShareApp => new Command(() =>
@@ -372,6 +405,17 @@ public async void OnEnabled()
await StartExposureNotificationAsync();
+ _ = Task.Run(async () => {
+ try
+ {
+ await exposureDetectionBackgroundService.ExposureDetectionAsync();
+ }
+ finally
+ {
+ await UpdateView();
+ }
+ });
+
loggerService.EndMethod();
}
diff --git a/Covid19Radar/Covid19Radar/ViewModels/HomePage/NotifyOtherPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HomePage/NotifyOtherPageViewModel.cs
index ec41429e5..04135f4cd 100644
--- a/Covid19Radar/Covid19Radar/ViewModels/HomePage/NotifyOtherPageViewModel.cs
+++ b/Covid19Radar/Covid19Radar/ViewModels/HomePage/NotifyOtherPageViewModel.cs
@@ -13,7 +13,6 @@
using Covid19Radar.Common;
using Covid19Radar.Resources;
using System.Threading.Tasks;
-using System.IO;
using System.Collections.Generic;
using Chino;
using System.Net;
@@ -121,6 +120,9 @@ public DateTime DiagnosisDate
private int errorCount { get; set; }
+ // TODO: Save and use for revoke operation.
+ private string idempotencyKey = Guid.NewGuid().ToString();
+
public NotifyOtherPageViewModel(
INavigationService navigationService,
ILoggerService loggerService,
@@ -219,16 +221,17 @@ await UserDialogs.Instance.AlertAsync(
AppResources.NotifyOtherPageDiagReturnHomeTitle,
AppResources.ButtonOk
);
- UserDialogs.Instance.HideLoading();
await NavigationService.NavigateAsync(Destination.HomePage.ToPath());
loggerService.Error($"Exceeded the number of trials.");
- loggerService.EndMethod();
return;
}
loggerService.Info($"Number of attempts to submit diagnostic number. ({errorCount + 1} of {AppConstants.MaxErrorCount})");
+ // UserDialogs.Instance.Loading must be executed in MainThread.
+ UserDialogs.Instance.ShowLoading(AppResources.LoadingTextRegistering);
+
if (errorCount > 0)
{
await UserDialogs.Instance.AlertAsync(AppResources.NotifyOtherPageDiag3Message,
@@ -250,6 +253,7 @@ await UserDialogs.Instance.AlertAsync(
);
errorCount++;
loggerService.Error($"No diagnostic number entered.");
+ UserDialogs.Instance.HideLoading();
return;
}
@@ -262,6 +266,7 @@ await UserDialogs.Instance.AlertAsync(
);
errorCount++;
loggerService.Error($"Incorrect process number format.");
+ UserDialogs.Instance.HideLoading();
return;
}
@@ -275,25 +280,58 @@ await UserDialogs.Instance.AlertAsync(
AppResources.NotifyOtherPageDiag6Title,
AppResources.ButtonOk
);
- UserDialogs.Instance.HideLoading();
await NavigationService.NavigateAsync("/" + nameof(MenuPage) + "/" + nameof(NavigationPage) + "/" + nameof(HomePage));
loggerService.Warning($"Exposure notification is disable.");
+ UserDialogs.Instance.HideLoading();
return;
}
- await SubmitDiagnosisKeys();
+ HttpStatusCode httpResult = await SubmitDiagnosisKeys();
+
+ UserDialogs.Instance.HideLoading();
+
+ ShowResult(httpResult);
+
+ if (httpResult != HttpStatusCode.OK)
+ {
+ errorCount++;
+ }
+ }
+ catch (ENException exception)
+ {
+ loggerService.Exception("GetTemporaryExposureKeyHistoryAsync", exception);
+
+ if (exception.Code == ENException.Code_iOS.NotAuthorized)
+ {
+ loggerService.Info("GetTekHistory request is declined by user.");
+
+ UserDialogs.Instance.HideLoading();
+
+ await UserDialogs.Instance.AlertAsync(
+ null,
+ AppResources.NotifyOtherPageDiag2Title,
+ AppResources.ButtonOk
+ );
+ }
+ else
+ {
+ UserDialogs.Instance.HideLoading();
+ }
+
}
catch (Exception ex)
{
+ errorCount++;
+
UserDialogs.Instance.HideLoading();
- errorCount++;
- UserDialogs.Instance.Alert(
- AppResources.NotifyOtherPageDialogExceptionText,
+ await UserDialogs.Instance.AlertAsync(
+ AppResources.NotifyOther_Dialog_NoConnection,
AppResources.NotifyOtherPageDialogExceptionTitle,
AppResources.ButtonOk
- );
+ );
+
loggerService.Exception("Failed to submit DiagnosisKeys.", ex);
}
finally
@@ -302,78 +340,47 @@ await UserDialogs.Instance.AlertAsync(
}
}));
- private async Task SubmitDiagnosisKeys()
+ private async Task SubmitDiagnosisKeys()
{
loggerService.Info($"Submit DiagnosisKeys.");
- try
- {
- List temporaryExposureKeyList
- = await exposureNotificationApiService.GetTemporaryExposureKeyHistoryAsync();
-
- loggerService.Info($"TemporaryExposureKeys-count: {temporaryExposureKeyList.Count()}");
-
- IList filteredTemporaryExposureKeyList
- = TemporaryExposureKeyUtils.FiilterTemporaryExposureKeys(
- temporaryExposureKeyList,
- _diagnosisDate,
- AppConstants.DaysToSendTek,
- loggerService
- );
-
- loggerService.Info($"FilteredTemporaryExposureKeys-count: {filteredTemporaryExposureKeyList.Count()}");
-
- // Set reportType
- foreach (var tek in filteredTemporaryExposureKeyList)
- {
- tek.ReportType = DEFAULT_REPORT_TYPE;
- }
-
- UserDialogs.Instance.ShowLoading(AppResources.LoadingTextRegistering);
+ List temporaryExposureKeyList
+ = await exposureNotificationApiService.GetTemporaryExposureKeyHistoryAsync();
- // TODO: Save and use revoke operation.
- string idempotencyKey = Guid.NewGuid().ToString();
+ loggerService.Info($"TemporaryExposureKeys-count: {temporaryExposureKeyList.Count()}");
- IList httpStatusCodes = await diagnosisKeyRegisterServer.SubmitDiagnosisKeysAsync(
+ IList filteredTemporaryExposureKeyList
+ = TemporaryExposureKeyUtils.FiilterTemporaryExposureKeys(
+ temporaryExposureKeyList,
_diagnosisDate,
- filteredTemporaryExposureKeyList,
- ProcessingNumber,
- idempotencyKey
+ AppConstants.DaysToSendTek,
+ loggerService
);
- foreach(var statusCode in httpStatusCodes)
- {
- loggerService.Info($"HTTP status is {httpStatusCodes}({(int)statusCode}).");
-
- // Mainly, we expect that SubmitDiagnosisKeysAsync returns one result.
- // Multiple-results is for debug use only.
- ShowResult(statusCode);
- }
+ loggerService.Info($"FilteredTemporaryExposureKeys-count: {filteredTemporaryExposureKeyList.Count()}");
- if (httpStatusCodes.Any(statusCode => statusCode != HttpStatusCode.OK))
- {
- errorCount++;
- }
- }
- catch (ENException exception)
- {
- loggerService.Exception("GetTemporaryExposureKeyHistoryAsync", exception);
- }
- catch (Exception exception)
- {
- loggerService.Exception("SubmitDiagnosisKeys", exception);
- }
- finally
+ // Set reportType
+ foreach (var tek in filteredTemporaryExposureKeyList)
{
- UserDialogs.Instance.HideLoading();
+ tek.ReportType = DEFAULT_REPORT_TYPE;
}
+
+ return await diagnosisKeyRegisterServer.SubmitDiagnosisKeysAsync(
+ _diagnosisDate,
+ filteredTemporaryExposureKeyList,
+ ProcessingNumber,
+ idempotencyKey
+ );
}
private async void ShowResult(HttpStatusCode httpStatusCode)
{
+ loggerService.Info($"HTTP status is {httpStatusCode}({(int)httpStatusCode}).");
+
switch (httpStatusCode)
{
case HttpStatusCode.OK:
+ case HttpStatusCode.NoContent:
// Success
loggerService.Info($"Successfully submit DiagnosisKeys.");
@@ -449,9 +456,54 @@ public async void OnGetTekHistoryAllowed()
{
loggerService.StartMethod();
- await SubmitDiagnosisKeys();
+ try
+ {
+ using (UserDialogs.Instance.Loading(AppResources.LoadingTextRegistering))
+ {
+ HttpStatusCode httpResult = await SubmitDiagnosisKeys();
+
+ ShowResult(httpResult);
+
+ if (httpResult != HttpStatusCode.OK)
+ {
+ errorCount++;
+ }
+ }
+ }
+ catch (ENException exception)
+ {
+ loggerService.Exception("GetTemporaryExposureKeyHistoryAsync", exception);
+ }
+ catch (Exception ex)
+ {
+ errorCount++;
+
+ await UserDialogs.Instance.AlertAsync(
+ AppResources.NotifyOtherPageDialogExceptionText,
+ AppResources.NotifyOtherPageDialogExceptionTitle,
+ AppResources.ButtonOk
+ );
+ loggerService.Exception("Failed to submit DiagnosisKeys.", ex);
+ }
+ finally
+ {
+ loggerService.EndMethod();
+ }
+ }
+
+ public async void OnGetTekHistoryDecline()
+ {
+ loggerService.StartMethod();
+
+ loggerService.Info("GetTekHistory request is declined by user.");
+ await UserDialogs.Instance.AlertAsync(
+ null,
+ AppResources.NotifyOtherPageDiag2Title,
+ AppResources.ButtonOk
+ );
loggerService.EndMethod();
}
+
}
}
diff --git a/Covid19Radar/Covid19Radar/ViewModels/HomePage/ThankYouNotifyOtherPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/HomePage/ThankYouNotifyOtherPageViewModel.cs
deleted file mode 100644
index e1ebd84d6..000000000
--- a/Covid19Radar/Covid19Radar/ViewModels/HomePage/ThankYouNotifyOtherPageViewModel.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-using Covid19Radar.Common;
-using Covid19Radar.Services;
-using Covid19Radar.Services.Logs;
-using Prism.Navigation;
-using Xamarin.Forms;
-
-namespace Covid19Radar.ViewModels
-{
- public class ThankYouNotifyOtherPageViewModel : ViewModelBase
- {
- private readonly ILoggerService loggerService;
-
- public ThankYouNotifyOtherPageViewModel(INavigationService navigationService, ILoggerService loggerService) : base(navigationService)
- {
- Title = Resources.AppResources.TitileUserStatusSettings;
- this.loggerService = loggerService;
- }
- public Command OnClickShareApp => new Command(() =>
- {
- loggerService.StartMethod();
-
- AppUtils.PopUpShare();
-
- loggerService.EndMethod();
- });
-
- }
-}
diff --git a/Covid19Radar/Covid19Radar/ViewModels/Settings/DebugPageViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/Settings/DebugPageViewModel.cs
index 2c6f6646d..1c7a494b6 100644
--- a/Covid19Radar/Covid19Radar/ViewModels/Settings/DebugPageViewModel.cs
+++ b/Covid19Radar/Covid19Radar/ViewModels/Settings/DebugPageViewModel.cs
@@ -4,13 +4,19 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
using System.Threading.Tasks;
using Acr.UserDialogs;
+using Chino;
using Covid19Radar.Common;
using Covid19Radar.Repository;
using Covid19Radar.Services;
using Prism.Navigation;
+using Xamarin.Essentials;
using Xamarin.Forms;
namespace Covid19Radar.ViewModels
@@ -25,6 +31,7 @@ public class DebugPageViewModel : ViewModelBase
private readonly AbsExposureDetectionBackgroundService _exposureDetectionBackgroundService;
private readonly ICloseApplicationService _closeApplicationService;
private readonly IServerConfigurationRepository _serverConfigurationRepository;
+ private readonly ILocalNotificationService _localNotificationService;
private string _debugInfo;
public string DebugInfo
@@ -144,7 +151,8 @@ public DebugPageViewModel(
AbsExposureNotificationApiService exposureNotificationApiService,
AbsExposureDetectionBackgroundService exposureDetectionBackgroundService,
ICloseApplicationService closeApplicationService,
- IServerConfigurationRepository serverConfigurationRepository
+ IServerConfigurationRepository serverConfigurationRepository,
+ ILocalNotificationService localNotificationService
) : base(navigationService)
{
Title = "Title:Debug";
@@ -156,6 +164,7 @@ IServerConfigurationRepository serverConfigurationRepository
_exposureDetectionBackgroundService = exposureDetectionBackgroundService;
_closeApplicationService = closeApplicationService;
_serverConfigurationRepository = serverConfigurationRepository;
+ _localNotificationService = localNotificationService;
}
public override async void Initialize(INavigationParameters parameters)
@@ -200,6 +209,59 @@ public override async void Initialize(INavigationParameters parameters)
await UpdateInfo("StopExposureNotification");
});
+ public Command OnClickShowExposureNotification => new Command(async () =>
+ {
+ await _localNotificationService.ShowExposureNotificationAsync();
+ });
+
+ public Command OnClickExportExposureWindow => new Command(async () =>
+ {
+ var exposureWindows = await _exposureDataRepository.GetExposureWindowsAsync();
+ var csv = ConvertCsv(exposureWindows);
+ var hashString = ConvertSha256(csv);
+
+ var fileName = $"exposure_window-{DeviceInfo.Name}-{hashString}.csv";
+ var file = Path.Combine(FileSystem.CacheDirectory, fileName);
+ File.WriteAllText(file, csv);
+
+ var shareFile = new ShareFile(file);
+ await Share.RequestAsync(new ShareFileRequest
+ {
+ File = shareFile
+ });
+ });
+
+ private string ConvertCsv(List exposureWindows)
+ {
+ var flattenWindowLines = exposureWindows.Select((window, index) =>
+ {
+ var humanReadableDateMillisSinceEpoch = DateTimeOffset.UnixEpoch
+ .AddMilliseconds(window.DateMillisSinceEpoch).UtcDateTime
+ .ToLocalTime()
+ .ToString("D", CultureInfo.CurrentCulture);
+ var connmaSeparatedWindow = $"{index},{window.CalibrationConfidence},{humanReadableDateMillisSinceEpoch},{window.Infectiousness},{window.ReportType}";
+ var flattenWindow = window.ScanInstances.Select(scanInstance =>
+ {
+ var connmaSeparatedScanInstance = $"{scanInstance.MinAttenuationDb},{scanInstance.SecondsSinceLastScan},{scanInstance.TypicalAttenuationDb}";
+ return $"{connmaSeparatedWindow},{connmaSeparatedScanInstance}";
+ });
+ return String.Join("\n", flattenWindow);
+ });
+
+ var csv = new StringBuilder();
+ csv.AppendLine("ExposureWindowIndex,CalibrationConfidence,DateMillisSinceEpoch,Infectiousness,ReportType,MinAttenuationDb,SecondsSinceLastScan,TypicalAttenuationDb");
+ csv.AppendLine(String.Join("\n", flattenWindowLines));
+ return csv.ToString();
+ }
+
+ private string ConvertSha256(string text)
+ {
+ using var sha = SHA256.Create();
+ var textBytes = Encoding.UTF8.GetBytes(text);
+ var hash = sha.ComputeHash(textBytes);
+ return BitConverter.ToString(hash).Replace("-", string.Empty);
+ }
+
public Command OnClickRemoveStartDate => new Command(async () =>
{
_userDataRepository.RemoveStartDate();
diff --git a/Covid19Radar/Covid19Radar/ViewModels/Tutorial/TutorialPage5ViewModel.cs b/Covid19Radar/Covid19Radar/ViewModels/Tutorial/TutorialPage5ViewModel.cs
deleted file mode 100644
index beede3430..000000000
--- a/Covid19Radar/Covid19Radar/ViewModels/Tutorial/TutorialPage5ViewModel.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-using Covid19Radar.Services.Logs;
-using Covid19Radar.Views;
-using Prism.Navigation;
-using Xamarin.Forms;
-
-namespace Covid19Radar.ViewModels
-{
- public class TutorialPage5ViewModel : ViewModelBase
- {
- private readonly ILoggerService loggerService;
-
- public TutorialPage5ViewModel(INavigationService navigationService, ILoggerService loggerService) : base(navigationService)
- {
- this.loggerService = loggerService;
-
- }
-
- public Command OnClickEnable => new Command(async () =>
- {
- loggerService.StartMethod();
- await NavigationService.NavigateAsync(nameof(TutorialPage6));
- loggerService.EndMethod();
- });
-
- public Command OnClickDisable => new Command(async () =>
- {
- loggerService.StartMethod();
- await NavigationService.NavigateAsync(nameof(TutorialPage6));
- loggerService.EndMethod();
- });
- }
-}
diff --git a/Covid19Radar/Covid19Radar/Views/ExceptionPage.xaml b/Covid19Radar/Covid19Radar/Views/ExceptionPage.xaml
deleted file mode 100644
index 80b98f2fb..000000000
--- a/Covid19Radar/Covid19Radar/Views/ExceptionPage.xaml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Covid19Radar/Covid19Radar/Views/ExceptionPage.xaml.cs b/Covid19Radar/Covid19Radar/Views/ExceptionPage.xaml.cs
deleted file mode 100644
index e75e4c5fd..000000000
--- a/Covid19Radar/Covid19Radar/Views/ExceptionPage.xaml.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xamarin.Forms;
-using Xamarin.Forms.Xaml;
-
-namespace Covid19Radar.Views
-{
- [XamlCompilation(XamlCompilationOptions.Compile)]
-
- public partial class ExceptionPage : ContentPage
- {
- public ExceptionPage()
- {
- InitializeComponent();
- }
- }
-}
\ No newline at end of file
diff --git a/Covid19Radar/Covid19Radar/Views/ExposureCheck/ExposureCheckPage.xaml.cs b/Covid19Radar/Covid19Radar/Views/ExposureCheck/ExposureCheckPage.xaml.cs
index 74bc5dc9b..924e71499 100644
--- a/Covid19Radar/Covid19Radar/Views/ExposureCheck/ExposureCheckPage.xaml.cs
+++ b/Covid19Radar/Covid19Radar/Views/ExposureCheck/ExposureCheckPage.xaml.cs
@@ -1,6 +1,8 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
+using Covid19Radar.Model;
+using Prism.Navigation;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
@@ -9,6 +11,21 @@ namespace Covid19Radar.Views
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ExposureCheckPage : ContentPage
{
+ public const string ExposureRiskCalculationConfigurationKey = "exposure_risk_calculation_configuration";
+
+ public static INavigationParameters BuildNavigationParams(
+ V1ExposureRiskCalculationConfiguration exposureRiskCalculationConfiguration,
+ INavigationParameters? baseParam = null
+ )
+ {
+ var param = new NavigationParameters();
+ param.CopyFrom(baseParam);
+
+ param.Add(ExposureRiskCalculationConfigurationKey, exposureRiskCalculationConfiguration);
+
+ return param;
+ }
+
public ExposureCheckPage()
{
InitializeComponent();
diff --git a/Covid19Radar/Covid19Radar/Views/ExposureCheck/LowRiskContactLayout.xaml b/Covid19Radar/Covid19Radar/Views/ExposureCheck/LowRiskContactLayout.xaml
index 288e86697..503824893 100644
--- a/Covid19Radar/Covid19Radar/Views/ExposureCheck/LowRiskContactLayout.xaml
+++ b/Covid19Radar/Covid19Radar/Views/ExposureCheck/LowRiskContactLayout.xaml
@@ -66,7 +66,8 @@
AutomationProperties.IsInAccessibleTree="True"
VerticalOptions="Center"
Style="{StaticResource DefaultLabelCaption}"
- Text="{x:Static resources:AppResources.LowRiskContactPageHeaderTextSuffix}">
+ Text="{Binding LowRiskContactPageHeaderTextSuffix}"
+ >
@@ -82,12 +83,15 @@
+ Text="{Binding DateTimeString}"
+ Margin="0, 0, 0, 10"
+ />
@@ -101,7 +105,7 @@
Padding="20">
+ Text="{Binding LowRiskContactPageAnnotationDecription}" />
diff --git a/Covid19Radar/Covid19Radar/Views/HomePage/NotifyOtherPage.xaml b/Covid19Radar/Covid19Radar/Views/HomePage/NotifyOtherPage.xaml
index 7a9823f73..1f9c658d1 100644
--- a/Covid19Radar/Covid19Radar/Views/HomePage/NotifyOtherPage.xaml
+++ b/Covid19Radar/Covid19Radar/Views/HomePage/NotifyOtherPage.xaml
@@ -16,7 +16,7 @@
ios:Page.UseSafeArea="true"
prism:ViewModelLocator.AutowireViewModel="True"
Style="{StaticResource DefaultPageStyle}"
- Visual="Material">
+ >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Covid19Radar/Covid19Radar/Views/HomePage/ThankYouNotifyOtherPage.xaml.cs b/Covid19Radar/Covid19Radar/Views/HomePage/ThankYouNotifyOtherPage.xaml.cs
deleted file mode 100644
index b16023fae..000000000
--- a/Covid19Radar/Covid19Radar/Views/HomePage/ThankYouNotifyOtherPage.xaml.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-using Covid19Radar.Common;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xamarin.Essentials;
-using Xamarin.Forms;
-using Xamarin.Forms.Xaml;
-
-namespace Covid19Radar.Views
-{
- [XamlCompilation(XamlCompilationOptions.Compile)]
- public partial class ThankYouNotifyOtherPage : ContentPage
- {
- public ThankYouNotifyOtherPage()
- {
- InitializeComponent();
- }
-
- }
-}
\ No newline at end of file
diff --git a/Covid19Radar/Covid19Radar/Views/Settings/DebugPage.xaml b/Covid19Radar/Covid19Radar/Views/Settings/DebugPage.xaml
index c219d91f4..6a4a1ae42 100644
--- a/Covid19Radar/Covid19Radar/Views/Settings/DebugPage.xaml
+++ b/Covid19Radar/Covid19Radar/Views/Settings/DebugPage.xaml
@@ -72,6 +72,14 @@
Command="{Binding Path=OnClickStopExposureNotification}"
Style="{StaticResource DefaultButton}"
Text="StopExposureNotification" />
+
+
-
-