Skip to content
This repository has been archived by the owner on Apr 12, 2023. It is now read-only.

Commit

Permalink
Improved notification function that did not work normally even if the…
Browse files Browse the repository at this point in the history
…re was close contact with a positive person on android app.

Improved the case in which the application seems to be reset (usage start date is reset, the terms of use screen is displayed again, etc). when the application or OS is updated on some devices.
Fixed the issue that the users who had close contact (within 1 meter for 15 minutes or more ) with a positive person were notified of the proximity to a positive person who did not meet the above condition on android app.
  • Loading branch information
cocoa-dev committed Feb 18, 2021
1 parent cf58f22 commit 047b12b
Show file tree
Hide file tree
Showing 61 changed files with 2,363 additions and 1,536 deletions.
2 changes: 2 additions & 0 deletions Covid19Radar/Covid19Radar.Android/Covid19Radar.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@
<Compile Include="Services\Logs\LogPathServiceAndroid.cs" />
<Compile Include="Services\Logs\LogPeriodicDeleteServiceAndroid.cs" />
<Compile Include="Renderers\CustomDatePickerRenderer.cs" />
<Compile Include="Services\PreferencesService.cs" />
<Compile Include="Services\SecureStorageServiceAndroid.cs" />
</ItemGroup>
<ItemGroup>
<None Include="appcenter-pre-build.sh" />
Expand Down
12 changes: 4 additions & 8 deletions Covid19Radar/Covid19Radar.Android/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,11 @@
using Prism.Ioc;
using Android.Runtime;
using Android.Content;
using Covid19Radar.Model;
using System.Collections.Generic;
using System.Linq;
using System;
using Covid19Radar.Common;
using Covid19Radar.Droid.Services.Logs;
using Covid19Radar.Services.Logs;
using System.Threading.Tasks;
using Xamarin.Forms;
using Acr.UserDialogs;
using Covid19Radar.Renderers;
using Covid19Radar.Services;
using Covid19Radar.Droid.Services;
//using Plugin.LocalNotification;

namespace Covid19Radar.Droid
Expand Down Expand Up @@ -62,6 +56,8 @@ public void RegisterTypes(IContainerRegistry containerRegistry)
{
// Services
containerRegistry.RegisterSingleton<ILogPathDependencyService, LogPathServiceAndroid>();
containerRegistry.RegisterSingleton<ISecureStorageDependencyService, SecureStorageServiceAndroid>();
containerRegistry.RegisterSingleton<IPreferencesService, PreferencesService>();
}
}

Expand Down
154 changes: 154 additions & 0 deletions Covid19Radar/Covid19Radar.Android/Services/PreferencesService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System;
using Covid19Radar.Services;
using Covid19Radar.Services.Logs;

namespace Covid19Radar.Droid.Services
{
public class PreferencesService : IPreferencesService
{
private readonly ILoggerService loggerService;

public PreferencesService(ILoggerService loggerService)
{
this.loggerService = loggerService;
}

public bool ContainsKey(string key)
{
var context = Android.App.Application.Context;
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private);
return preference.Contains(key);
}

public T GetValue<T>(string key, T defaultValue)
{
lock (this)
{
loggerService.StartMethod();
loggerService.Info($"key={key}, type={typeof(T)}");

if (!ContainsKey(key))
{
loggerService.EndMethod();
return defaultValue;
}

var context = Android.App.Application.Context;
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private);
try
{
object value = null;
if (defaultValue == null)
{
value = preference.GetString(key, null);
return (T)value;
}

switch (defaultValue)
{
case int i:
value = preference.GetInt(key, i);
break;
case bool b:
value = preference.GetBoolean(key, b);
break;
case float f:
value = preference.GetFloat(key, f);
break;
case string s:
value = preference.GetString(key, s);
break;
case DateTime d:
var valueString = preference.GetString(key, d.ToString());
value = DateTime.Parse(valueString);
break;
default:
loggerService.Info("Type is not supported.");
value = defaultValue;
break;
}

loggerService.EndMethod();
return (T)value;
}
catch (Exception)
{
loggerService.Error($"Failed to get value of {key}");
loggerService.EndMethod();
return defaultValue;
}
}
}

public void SetValue<T>(string key, T value)
{
lock (this)
{
loggerService.StartMethod();
loggerService.Info($"key={key}, type={typeof(T)}");

var context = Android.App.Application.Context;
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private);
var editor = preference.Edit();

bool result;

if (ContainsKey(key) && value == null)
{
editor.Remove(key);
result = editor.Commit();
}
else
{
switch (value)
{
case int i:
editor.PutInt(key, i);
break;
case bool b:
editor.PutBoolean(key, b);
break;
case float f:
editor.PutFloat(key, f);
break;
case string s:
editor.PutString(key, s);
break;
case DateTime d:
var valueString = d.ToString();
editor.PutString(key, valueString);
break;
}
result = editor.Commit();
}

if (!result)
{
loggerService.Error($"Failed to save value of {key}");
}

loggerService.EndMethod();
}
}

public void RemoveValue(string key)
{
lock (this)
{
loggerService.StartMethod();

if (ContainsKey(key))
{
loggerService.Info($"key={key}");

var context = Android.App.Application.Context;
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private);
var editor = preference.Edit();
editor.Remove(key).Commit();
}

loggerService.EndMethod();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using System;
using Android.Content;
using Android.Security.Keystore;
using Covid19Radar.Droid.Services;
using Covid19Radar.Services;
using Java.Security;
using Javax.Crypto;
using Javax.Crypto.Spec;
using Xamarin.Essentials;
using Xamarin.Forms;

[assembly: Dependency(typeof(SecureStorageServiceAndroid))]
namespace Covid19Radar.Droid.Services
{
public class SecureStorageServiceAndroid : ISecureStorageDependencyService
{
private readonly string Alias = $"{AppInfo.PackageName}.securestorage";
private readonly int IvLength = 12;
private readonly int GcmTagLength = 128;
private readonly string KeyStoreType = "AndroidKeyStore";
private readonly string CipherTransformation = "AES/GCM/NoPadding";

private readonly ISharedPreferences sharedPreferences;

public SecureStorageServiceAndroid()
{
sharedPreferences = Android.App.Application.Context.GetSharedPreferences(Alias, FileCreationMode.Private);
}

public bool ContainsKey(string key)
{
return sharedPreferences.Contains(key);
}

public byte[] GetBytes(string key)
{
byte[] result = null;

if (sharedPreferences.Contains(key))
{
var loadedText = sharedPreferences.GetString(key, "");
var loadedBytes = Convert.FromBase64String(loadedText);
if (loadedBytes.Length <= IvLength)
{
throw new InvalidOperationException("Invalid read data.");
}

var iv = new byte[IvLength];
Array.Copy(loadedBytes, 0, iv, 0, iv.Length);

var encryptedBytes = new byte[loadedBytes.Length - iv.Length];
Array.Copy(loadedBytes, iv.Length, encryptedBytes, 0, encryptedBytes.Length);

var keyStore = KeyStore.GetInstance(KeyStoreType);
keyStore.Load(null);

var storeKey = keyStore.GetKey(Alias, null);
if (storeKey == null)
{
throw new InvalidOperationException("Could not get the KeyStore key.");
}

var cipher = Cipher.GetInstance(CipherTransformation);
cipher.Init(CipherMode.DecryptMode, storeKey, new GCMParameterSpec(GcmTagLength, iv));
result = cipher.DoFinal(encryptedBytes);
}

return result;
}

public void Remove(string key)
{
if (sharedPreferences.Contains(key))
{
var edit = sharedPreferences.Edit();
edit.Remove(key);
edit.Commit();
}
}

public void SetBytes(string key, byte[] bytes)
{
var keyStore = KeyStore.GetInstance(KeyStoreType);
keyStore.Load(null);

var storeKey = keyStore.GetKey(Alias, null);
if (storeKey == null)
{
var generator = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KeyStoreType);
var spec = new KeyGenParameterSpec.Builder(Alias, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(KeyProperties.BlockModeGcm)
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingNone)
.SetRandomizedEncryptionRequired(false)
.Build();

generator.Init(spec);
generator.GenerateKey();

storeKey = keyStore.GetKey(Alias, null);
if (storeKey == null)
{
throw new InvalidOperationException("Failed KeyStore key generation.");
}
}

var iv = new byte[IvLength];
var randam = new SecureRandom();
randam.NextBytes(iv);

var cipher = Cipher.GetInstance(CipherTransformation);
cipher.Init(CipherMode.EncryptMode, storeKey, new GCMParameterSpec(GcmTagLength, iv));

var encryptedBytes = cipher.DoFinal(bytes);

var saveBytes = new byte[iv.Length + encryptedBytes.Length];
Array.Copy(iv, 0, saveBytes, 0, iv.Length);
Array.Copy(encryptedBytes, 0, saveBytes, iv.Length, encryptedBytes.Length);

var saveText = Convert.ToBase64String(saveBytes);

var edit = sharedPreferences.Edit();
edit.PutString(key, saveText);
edit.Commit();
}
}
}
6 changes: 6 additions & 0 deletions Covid19Radar/Covid19Radar.Android/appcenter-pre-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ sed -i '' "s/LOG_STORAGE_ACCOUNT_NAME/$LOG_STORAGE_ACCOUNT_NAME/g" $APP_CONSTANT
cat $APP_CONSTANT_FILE

echo "Updated id!"

# To avoid the following
# https://github.com/xamarin/xamarin-android/issues/5499
${ANDROID_HOME}/tools/bin/sdkmanager --uninstall "ndk-bundle"
${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;21.3.6528147"
ln -s ${ANDROID_HOME}/ndk/21.3.6528147 ${ANDROID_HOME}/ndk-bundle
6 changes: 5 additions & 1 deletion Covid19Radar/Covid19Radar.iOS/AppDelegate.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Covid19Radar.iOS.Services.Logs;
using Covid19Radar.iOS.Services;
using Covid19Radar.iOS.Services.Logs;
using Covid19Radar.Services;
using Covid19Radar.Services.Logs;
using Foundation;
using Prism;
Expand Down Expand Up @@ -60,6 +62,8 @@ public void RegisterTypes(IContainerRegistry containerRegistry)
{
// Services
containerRegistry.RegisterSingleton<ILogPathDependencyService, LogPathServiceIos>();
containerRegistry.RegisterSingleton<ISecureStorageDependencyService, SecureStorageServiceIos>();
containerRegistry.RegisterSingleton<IPreferencesService, PreferencesService>();
}
}

Expand Down
2 changes: 2 additions & 0 deletions Covid19Radar/Covid19Radar.iOS/Covid19Radar.iOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@
<Compile Include="Services\Logs\LogPathServiceIos.cs" />
<Compile Include="Services\Logs\LogPeriodicDeleteServiceIos.cs" />
<Compile Include="Renderers\CustomDatePickerRenderer.cs" />
<Compile Include="Services\PreferencesService.cs" />
<Compile Include="Services\SecureStorageServiceIos.cs" />
</ItemGroup>
<ItemGroup>
<ImageAsset Include="Assets.xcassets\Contents.json">
Expand Down
Loading

0 comments on commit 047b12b

Please sign in to comment.