GithubHelp home page GithubHelp logo

keiji / chino Goto Github PK

View Code? Open in Web Editor NEW
7.0 4.0 2.0 1.88 MB

Cappuccino is an yet another Exposure Notification Library for COCOA.

License: Other

C# 99.64% Shell 0.24% Dockerfile 0.12%
exposure-notification xamarin

chino's People

Contributors

kazuhiro4949 avatar keiji avatar kishikawakatsumi avatar runceel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

chino's Issues

リリースに向けたAPIの調整

Prism(Xamarin.Forms)での利用サンプルを作成した中で気づいた不明瞭なChinoのAPIを調整する。

Chino.iOSとしてSharedを持つ必要はない。必要な場合はiOSプロジェクト側で持てば足りる。

public static readonly ExposureNotificationClient Shared = new ExposureNotificationClient();

Init忘れの時にエラーメッセージを表示して欲しい。

public Task Init(string userExplanation)
{
UserExplanation = userExplanation;
return Task.Run(async () =>
{
await EnManager.ActivateAsync();
});
}

Handlerの設定とInitを同時にした方がわかりやすいので検討する。← BroadcastReceiverからアクセスする方法がないのでこのままにする。

Loggerはよくある名前と衝突するのでライブラリの外に出したくない(スコープを狭める?)。← スコープを狭めるとChino.Android/iOSからも使えないので名前をChinoLoggerに変える。

async付けたメソッドは名前の末尾にAsyncを付けるべき。

サンプルアプリでTEK取得の承認時に例外が発生する

ユーザー承認待ちのケースでTEKが0件変える時にも、ID計算のために0件のリストをLINQ(Max)で処理しようとしているのが原因。

private void UpdateId()
{
var latest = temporaryExposureKeys.Max(tek => tek.rollingStartNumber + tek.rollingPeriod);
Id = $"{_device}-{latest}";
}

System.InvalidOperationException: Sequence contains no elements
  at System.Linq.Enumerable.Max[TSource] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] selector) [0x0002b] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.Linq/src/System/Linq/Max.cs:620
  at Sample.Common.Model.TemporaryExposureKeys.UpdateId () [0x00001] in /Volumes/MHLW/repos/Chino/Sample.Common/Model/TemporaryExposureKeys.cs:54
  at Sample.Common.Model.TemporaryExposureKeys..ctor (System.Collections.Generic.IList`1[T] teks, System.DateTime generatedAt, Chino.ReportType defaultRportType, Chino.RiskLevel defaultTrasmissionRisk) [0x00057] in /Volumes/MHLW/repos/Chino/Sample.Common/Model/TemporaryExposureKeys.cs:49
  at Sample.Android.MainActivity.SaveTekHistoryAsync (System.Collections.Generic.List`1[T] temporaryExposureKeys) [0x00013] in /Volumes/MHLW/repos/Chino/Sample.Android/MainActivity.cs:219
  at Sample.Android.MainActivity.<OnCreate>b__14_1 (System.Object <p0>, System.EventArgs <p1>) [0x000cb] in /Volumes/MHLW/repos/Chino/Sample.Android/MainActivity.cs:72
  at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_0 (System.Object state) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1021
  at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in /Users/builder/azdo/_work/2/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:36
  at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in /Users/builder/azdo/_work/2/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:36
  at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in /Users/builder/azdo/_work/2/s/xamarin-android/src/Mono.Android/obj/Release/monoandroid10/android-30/mcw/Java.Lang.IRunnable.cs:90
  at at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.31(intptr,intptr)

Close条件

  • コードを修正する

Chino.iOS. ExposureNotificationClientの`IsTest`を廃止する

現在のCappuccinoは、iOS版のGetDiagnosisKeysAsyncGetTestDiagnosisKeysAsyncの呼び分けをIsTestの設定によって切り替えている。

if (!IsTest)
{
ENTemporaryExposureKey[] teks = await EnManager.Value.GetDiagnosisKeysAsync();
return teks.Select(tek => (TemporaryExposureKey)new PlatformTemporaryExposureKey(tek)).ToList();
}
else
{
ENTemporaryExposureKey[] teks = await EnManager.Value.GetTestDiagnosisKeysAsync();
return teks.Select(tek => (TemporaryExposureKey)new PlatformTemporaryExposureKey(tek)).ToList();
}

しかしこの方法ではバイナリ中にGetTestDiagnosisKeysAsyncの呼び出し経路が残った状態になるため、接触確認アプリのリリース審査で指摘を受ける可能性がCOCOA開発チームから示されている。

審査を円滑に進めるため、IsTestによる呼び分けを廃止して、ビルド構成Release・Debugによる呼び分けに変更する。

CappuccinoのバイナリをDebug/Release両方を提供して、ビルド時にどちらのnuget packageを利用するか切り替えできるようにする。

オープンソースライセンスを決定する

オープンソースのライセンスを決める必要がある。

COCOAのライセンスが MPL(Mozilla Public License)2.0 なので、それと互換性があるものにする。

候補としては、

COPYRIGHT HOLDER はCappuccino Authorsとしたい。

Close条件

  • ライセンスが決定すること
  • ライセンスが LICENSE としてリポジトリに追加されること
  • README.mdに License の項目を設けて、必要な記述を終えること

PackageReferenceへ移行

#2 で検討した結果(packages.configはもうメンテナンスされていないため)、PackageReferenceに移行する。

JSONライブラリの導入

ExposureConfigurationをJSONで取り扱えるようにしたい。

Close条件

  • 導入するJSONライブラリが決定すること
  • JSONライブラリを導入すること
  • LICENSEにJSONライブラリのエントリを記入すること
  • ExposureConfigurationにJSONキーを設定してシリアライズ、デシリアライズができること
  • テストコードを整備すること

[Android][v2] setDiagnosisKeysDataMapping の呼び出し回数制限を考慮する

ExposureNotificationClient#setDiagnosisKeysDataMapping は週 1 回という呼び出し回数の制限があります。
週 2 回以上呼び出すとステータスコードFAILED_RATE_LIMITEDの例外がスローされるようです。
https://developers.google.com/android/reference/com/google/android/gms/nearby/exposurenotification/ExposureNotificationClient#setDiagnosisKeysDataMapping(com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping)

Chino.Android の当該箇所

await EnClient.SetDiagnosisKeysDataMappingAsync(diagnosisKeysDataMapping);

を見るに、その考慮がなされていないように思います。
(見落としならばすみません)

例えば Google のサンプルでは、前回のマップと比較して同じならばsetDiagnosisKeysDataMappingを呼び出さない、ということをしています。
https://github.com/google/exposure-notifications-android/blob/610788eb3815d8ddb397332ba6f982308f7cde01/app/src/main/java/com/google/android/apps/exposurenotification/nearby/ProvideDiagnosisKeysWorker.java#L182

Fhi.Smittestopp.App では、前回呼び出し時刻を保持しておいて、7 日以内であれば何もしない、ということをしています。
https://github.com/folkehelseinstituttet/Fhi.Smittestopp.App/blob/7c8e687a24d7e9d0f27f0885ee6d48d8a2c2e41e/NDB.Covid19/NDB.Covid19.Droid/Utils/BackgroundFetchScheduler.cs#L100
https://github.com/folkehelseinstituttet/Fhi.Smittestopp.App/blob/7c8e687a24d7e9d0f27f0885ee6d48d8a2c2e41e/NDB.Covid19/NDB.Covid19.Droid/Utils/DiagnosisKeysDataMappingUtils.cs#L42

ちなみに、iOS においても、同様のマップは週 1 回しか更新できないようです
https://developer.apple.com/documentation/exposurenotification/enexposureconfiguration/3644389-infectiousnessfordayssinceonseto

You can’t change this property more often than once per week. During development, you can remove this limitation by adding the test entitlement com.apple.developer.exposure-notification-test to your project.

が、こちらは 2 回更新したときにエラーになるのか無視されるのか、どのような振舞いになるのかはドキュメントから見つけることができませんでした。

iOSとAndroidでExposureSummaryのattenuationDurationsの定義が異なる

Legacy-v1(ENv1)固有の事象のためCOCOA2への影響はない。

事象としては #36 と同様。
ExposureSummaryのgetAttenuationDurationsInMinutesおよびattenuationDurationsが、iOSでは「秒単位」であるのに対して、Androidでは「分単位」と定義が異なる。

ExposureInformation
https://developers.google.com/android/reference/com/google/android/gms/nearby/exposurenotification/ExposureSummary#getAttenuationDurationsInMinutes()

ENExposureDetectionSummary.attenuationDurations
https://developer.apple.com/documentation/exposurenotification/enexposuredetectionsummary/3586985-attenuationdurations

An array that contains the duration, in seconds, at certain attenuations, using an aggregated maximum exposures of 30 minutes.

これらの違いを吸収する仕組みが現在のchinoに実装されておらず、iOSではAttenuationDurationsInMinutesと言う変数名で値を取得しているので、接触確認後の処理が共通化できない。

Android版

  "exposure_summary": {
    "AttenuationDurationsInMinutes": [
      30,
      0,
      0
    ],

iOS版

  "exposure_summary": {
    "AttenuationDurationsInMinutes": [
      1800,
      1560,
      0
    ],

Close条件

  • コードを修正する(ミリ秒単位に統一)
  • 修正版をリリースする

[Android] ExposureStateBroadcastReceiver の状態を考慮する

ExposureStateBroadcastReceiver について、OnReceive内で呼び出している各タスクはOnReceiveを抜けた後も処理を続けることになるのだと思うのですが、 その場合以下にあるようにシステムによってアプリプロセスを終了させられてしまう可能性があるのではないかと思います。
(見落としならばすみません)
https://developer.android.com/guide/components/broadcasts?hl=ja#effects-process-state

例えば Google のサンプルでは、WorkManager を使っています。
https://github.com/google/exposure-notifications-android/blob/610788eb3815d8ddb397332ba6f982308f7cde01/app/src/main/java/com/google/android/apps/exposurenotification/nearby/ExposureNotificationBroadcastReceiver.java#L66
https://github.com/google/exposure-notifications-android/blob/610788eb3815d8ddb397332ba6f982308f7cde01/app/src/main/java/com/google/android/apps/exposurenotification/nearby/StateUpdatedWorker.java#L117

Xamarin.ExposureNotificationでは JobIntentService にまかせています。
https://github.com/xamarin/XamarinComponents/blob/e5ac2d06c8b6b2904ff119d8bae8b1d5e7cb2127/XPlat/ExposureNotification/source/Xamarin.ExposureNotification/CallbackService.android.cs#L28
https://github.com/xamarin/XamarinComponents/blob/main/XPlat/ExposureNotification/source/Xamarin.ExposureNotification/CallbackService.android.cs#L39

[iOS] 各APIを利用できるiOSのバージョンを記載する

ExposureNotification API(iOS)は、iOSのバージョンについてよって使えるAPIが異なる。

最終的にアプリ側で分岐することになるが、その判断基準となる対応バージョン情報をAPI側に記載する必要がある。

Close条件

  • コードに反映する
  • リリースする

リファクタリング

privateなメンバ変数は _ 始まりに統一する。
Breaking Changeは発生しない。

Close条件

  • コードを変更する

CatchできていないApiExceptionがある

cocoa-mhlw/cocoa#987 より。

言語設定の変更など端末の状態が大きく変わるタイミングでGoogle Play Servicesが再初期化され、そのタイミングでGoogle Play Servicesに接続しようとするとApiExceptionがthrowされる。

そのstatusCodeは8 InternalErrorであったり20 ConnectionSuspendedDuringCallであったりするが、今のCappuccinoはそれらのStatusはENExceptionの変換対象ではないので、そのままApiExceptionとしてthrowしてしまう。

ExposureInformation.Durationの取り扱い

ExposureInformation.Durationの値が、Googleは分単位なのに対してAppleは秒単位。

/// <summary>
/// Length of exposure in 5 minute increments, with a 30 minute maximum.
/// </summary>
public double Duration { get; set; }

Google
https://developers.google.com/android/reference/com/google/android/gms/nearby/exposurenotification/ExposureInformation#getDurationMinutes()

Length of exposure in 5 minute increments, with a 30 minute maximum.

Apple
https://developer.apple.com/documentation/exposurenotification/enexposureinfo/3583714-duration

When reporting the duration of an exposure, the values are stored as seconds rounded up to the next minute. A duration value caps at 30 minutes (1800 seconds).

増分は5分に当たる値。最大値は30分に当たる値であることは共通している。
現在は未調整なので、プラットフォームプロジェクト側で値の調整をする必要がある。

Android

  "exposure_informations": [
    {
      "AttenuationDurationsInMillis": [
        0,
        27000000,
        0
      ],
      "AttenuationValue": 55,
      "DateMillisSinceEpoch": 1627344000000,
      "Duration": 30.0,
      "TotalRiskScore": 256,
      "TransmissionRiskLevel": 4
    },

iOS

  "exposure_informations": [
    {
      "AttenuationDurationsInMillis": [
        1800000,
        0,
        0,
        0
      ],
      "AttenuationValue": 5,
      "DateMillisSinceEpoch": 1627084800000,
      "Duration": 1800.0,
      "TotalRiskScore": 200,
      "TransmissionRiskLevel": 4
    },

名前空間の調整

作り始めたときは同じ名前空間(Chino)の方が都合が良いと思っていたけど、Chino.Prismとかまで行くと同じにする意味はなかったのでわかりやすくする。

Close条件

  • コードの修正
  • リリース

iOSとAndroidでExposureInformationのDurationsの定義が異なる

ExposureInformationのAttenuationDurationsおよびAttenuationDurationsが、iOSでは「秒単位」であるのに対して、Androidでは「分単位」と定義が異なる。

ExposureInformation
https://developers.google.com/android/reference/com/google/android/gms/nearby/exposurenotification/ExposureInformation

ENExposureInfo.attenuationDurations
https://developer.apple.com/documentation/exposurenotification/enexposureinfo

An array that contains the duration, in seconds, at certain attenuations, using an aggregated maximum exposures of 30 minutes.

これらの違いを吸収する仕組みが現在のchinoに実装されておらず、iOSではInMinutesと言う変数名で値を取得しているので、接触確認後の処理が共通化できない。

Android版

public int[] AttenuationDurationsInMinutes => Source.GetAttenuationDurationsInMinutes();

  "exposure_informations": [
    {
      "AttenuationDurationsInMinutes": [
        1436,
        0,
        0
      ],
      "AttenuationValue": 26,
      "DateMillisSinceEpoch": 1622851200000,
      "Duration": 30.0,
      "TotalRiskScore": 256,
      "TransmissionRiskLevel": 4
    },

iOS版

public int[] AttenuationDurationsInMinutes => Source.AttenuationDurations;

  "exposure_informations": [
    {
      "AttenuationDurationsInMinutes": [
        1800,
        0,
        0,
        0
      ],
      "AttenuationValue": 4,
      "DateMillisSinceEpoch": 1622764800000,
      "Duration": 1800.0,
      "TotalRiskScore": 255,
      "TransmissionRiskLevel": 4
    },

Close条件

  • Durationの定義をどちらに寄せるか(秒か、分か)を決める
  • コードを修正する
  • 修正版をリリースする

Equalsを整備する

ExposureWindow, DailySummary, ExposureInformation, ExposureSummaryなどのクラスについてEqualsGetHashCodeメソッドが整備されていない。

Close条件

  • コードの追加
  • テストの追加
  • リリース

[CI] ビルドチェックを行う

現在、CIでCommon.Testsのユニットテストを実行しているが、加えてAndroidとiOSでのビルドチェックを行う。

  • Androidのビルドチェックが行われること
  • iOSのビルドチェックが行われること

[iOS] ENv2での動作確認

現在iOSで接触確認(Exposure Notification: EN)API v2の動作確認ができていない。
そのためEN v2を無効化(v1に固定)してある。

<key>ENAPIVersion</key>
<integer>1</integer>

ENv2を使用してDetectExposureを実行した場合、戻値のENExposureDetectionSummaryの内容がすべて0のものが返される。

ExposureDetectionSummary
AttenuationDurations: 
DaysSinceLastExposure: 0
MatchedKeyCount: 0
MaximumRiskScore: 0
MaximumRiskScoreFullRange: 0
RiskScoreSumFullRange: 0
Metadata: {
    attenuationDurations =     (
    );
    maximumRiskScoreFullRange = 0;
    riskScoreSumFullRange = 0;
}

ENv1を使用した場合、同じTEKsで実験しても、問題なく接触確認が機能する。

Androidでは問題なく、ENv2を使った接触確認が機能している。

Close条件

  • iOSでEN v2を使った接触確認ができること

現在の設定値

ExposureConfiguration

        // https://developer.apple.com/documentation/exposurenotification/enexposureconfiguration
        // https://developer.apple.com/documentation/exposurenotification/enexposureconfiguration/exposure_risk_value_calculation_in_exposurenotification_version_1
        public class AppleExposureConfiguration
        {
            // Configuring Duration

            #region These properties are available in iOS 12.5, and in iOS 13.5 and later.

            public double ImmediateDurationWeight { get; set; } = 100;
            public double MediumDurationWeight { get; set; } = 100;
            public double NearDurationWeight { get; set; } = 100;
            public double OtherDurationWeight { get; set; } = 100;

            public int DaysSinceLastExposureThreshold { get; set; } = 0;

            // Configuring Infectiousness

            // Must Specify v2
            public IDictionary<int, Infectiousness> InfectiousnessForDaysSinceOnsetOfSymptoms { get; set; } = new Dictionary<int, Infectiousness>() {
                { -14, Infectiousness.High },
                { -13, Infectiousness.High },
                { -12, Infectiousness.High },
                { -11, Infectiousness.High },
                { -10, Infectiousness.High },
                { -9, Infectiousness.High },
                { -8, Infectiousness.High },
                { -7, Infectiousness.High },
                { -6, Infectiousness.High },
                { -5, Infectiousness.High },
                { -4, Infectiousness.High },
                { -3, Infectiousness.High },
                { -2, Infectiousness.High },
                { -1, Infectiousness.High },
                { 0, Infectiousness.High },
                { 1, Infectiousness.High },
                { 2, Infectiousness.High },
                { 3, Infectiousness.High },
                { 4, Infectiousness.High },
                { 5, Infectiousness.High },
                { 6, Infectiousness.High },
                { 7, Infectiousness.High },
                { 8, Infectiousness.High },
                { 9, Infectiousness.High },
                { 10, Infectiousness.High },
                { 11, Infectiousness.High },
                { 12, Infectiousness.High },
                { 13, Infectiousness.High },
                { 14, Infectiousness.High },
            };

            public double InfectiousnessHighWeight { get; set; } = 100.0; // The range of this value is 0-250%
            public double InfectiousnessStandardWeight { get; set; } = 100.0; // The range of this value is 0-250%

            // Configuring Report Types

            public double ReportTypeConfirmedClinicalDiagnosisWeight { get; set; } = 100.0;
            public double ReportTypeConfirmedTestWeight { get; set; } = 100.0;
            public double ReportTypeRecursiveWeight { get; set; } = 100.0;
            public double ReportTypeSelfReportedWeight { get; set; } = 100.0;
            public ReportType ReportTypeNoneMap { get; set; } = ReportType.Unknown;

            public int[] AttenuationLevelValues { get; set; } = { 1, 2, 3, 4, 5, 6, 7, 8 };

            public int[] DaysSinceLastExposureLevelValues { get; set; } = { 1, 2, 3, 4, 5, 6, 7, 8 };

            public int[] DurationLevelValues { get; set; } = { 1, 2, 3, 4, 5, 6, 7, 8 };

            public int[] TransmissionRiskLevelValues { get; set; } = { 1, 2, 3, 4, 5, 6, 7, 8 };

            public IDictionary<object, object> Metadata { get; set; } = new Dictionary<object, object>();

            public byte MinimumRiskScore { get; set; } = 0;

            #endregion

            #region These properties are available in iOS 12.5, and in iOS 13.6 and later.

            public int[] AttenuationDurationThreshold { get; set; } = { 50, 70 };

            public double MinimumRiskScoreFullRange { get; set; } = 0.0;

            #endregion

DetectExposuresに使用したTEKs

testExport-12-records-1-of-1.zip

{"temporaryExposureKeys":[
{
    "key":"tJsz1lw5+DeEOLp3rtnbgg==",
    "rollingStartNumber":2696544,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"tYwc0Z0vIvW6TS4MGITW+Q==",
    "rollingStartNumber":2696688,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"/i3MbrjanFvU1PcgqSuvhw==",
    "rollingStartNumber":2696832,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"GmfZUSUXla2JwOYyEPhTaA==",
    "rollingStartNumber":2696976,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"vljPVh8MpsJkih7TlgZBsA==",
    "rollingStartNumber":2697120,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"z10UW6wzahpRn6dAgrmCKQ==",
    "rollingStartNumber":2697264,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"xiqd/4/Q5CCT0xGQUdsYhg==",
    "rollingStartNumber":2697408,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"59EgCCvAyyuuPM3LxLYaxQ==",
    "rollingStartNumber":2697984,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"biCadeEWdABv4Ei6r+H9kw==",
    "rollingStartNumber":2698128,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"aICg2wk8GZ8EDWIP9VdXuQ==",
    "rollingStartNumber":2698272,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"WecgOMdDMeusIzVZBlDLSA==",
    "rollingStartNumber":2698416,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
},
{
    "key":"6UIIIPp7z4K1fZyK9YhZzQ==",
    "rollingStartNumber":2698560,
    "rollingPeriod":144,
    "reportType":1,
    "transmissionRisk":8
}
]}

接触確認処理のキャンセル対応(CancellationToken)

cocoa-mhlw/cocoa#402 より。

外部からCancellationTokenSourceを受け取ってキャンセル対応できるようにする。

iOSの場合はDetectExposure周りで渡すことができる。

AndroidのProvideDiagnosisKeysには同様の処理はないため、ProvideDiagnosisKeysを実行してからBroadcastReceiverが呼ばれるまでの時間経過でタイムアウト・キャンセルができるようにする。

ExposureConfigurationの初期値を見直す

EN APIの接触確認の条件設定(ExposureConfiguration.cs)の各値が試行錯誤をしていたままになっているので、それぞれの設定値の初期値に変更する。

GoogleDiagnosisKeysDataMappingConfigAppleExposureV2Configuration. InfectiousnessForDaysSinceOnsetOfSymptomsのように初期値がnull、かつ必ず設定の必要がある項目については初期値を要検討(nullかデフォルトで値を入れておくか)。

Close条件

  • 見直しが終わること。
  • 初期値でないところはコメントを入れること

アクセススコープの見直しをする

現在、クラス、メソッド、プロパティその他のアクセススコープはpublicとprivateが主になっているが、publicのものについてはその必要があるかを検討して、スコープが適切になるように見直す。

Close条件

  • 現在publicなクラス、メソッド、プロパティのアクセススコープが見直しがされていること
  • publicが適当でないと判断した場合、適切なスコープに変更されていること

iOSとAndroidでDailySummaryの日付の概念が異なる

DailySummaryにある日付を示す値がiOSではDateと日付を示すのに対して、AndroidではgetDaysSinceEpoch()と「Epochからの経過日数」と定義が異なる。

DailySummary
https://developers.google.com/android/reference/com/google/android/gms/nearby/exposurenotification/DailySummary#getDaysSinceEpoch()

ENExposureDaySummary .date
https://developer.apple.com/documentation/exposurenotification/enexposuredaysummary/3644403-date

これらの違いを吸収する仕組みが現在のchinoに実装されておらず、iOSではDateMillisSinceEpochとして値を取得しているので、接触確認後の日付処理が正しく行われないことになる。

Android版

public long DaysSinceEpoch => Source.DaysSinceEpoch;

  "daily_summaries": [
    {
      "DaysSinceEpoch": 18784,
      "DaySummary": {
        "MaximumScore": 0.0,
        "ScoreSum": 0.0,
        "WeightedDurationSum": 75360.0
      },

iOS版

public long DaysSinceEpoch => Source.Date.GetDateMillisSinceEpoch();

  "daily_summaries": [
    {
      "DaysSinceEpoch": 1622937600000,
      "DaySummary": {
        "MaximumScore": 1860.0,
        "ScoreSum": 51660.0,
        "WeightedDurationSum": 51660.0
      },

Close条件

  • 日付の取り扱いをどちらに寄せるか(DaysSinceEpochか、DateMillisSinceEpochか)を決める
  • コードを修正する
  • 修正版をリリースする

[Sample] `daysSinceOnsetOfSymptoms`をサーバーに必ず送る

cocoa-mhlw/cocoa#334 (comment) に関連。

days_since_onset_of_symptoms について対応する上で、当初 keiji/en-calibration-server#2 で、症状が出ていないなどの理由で症状発生日が確定できないときに、daysSinceOnsetOfSymptomsのキーを値DAYS_SINCE_ONSET_OF_SYMPTOMS_UNKNOWN2147483647)として扱うようにしていた。

(iOSで規定されているENDaysSinceOnsetOfSymptomsUnknownはlong値の最大値であるため、int型のAndroidでは設定できない。そのため、Android側の値に合わせる形とした経緯がある)

この方法はiOSであれば問題なかったがInfectiousnessWhenDaysSinceOnsetMissingの取り扱いとなった。一方、Androidでは接触確認の結果が返されない事象が発生した。

days_since_onset_of_symptomsの値に想定されている(-14から14)までの範囲を設定して再テストしたところ、問題なく接触確認処理が行われ、結果を受け取ることができた。
このことから、Android版においてdays_since_onset_of_symptomsに設定する値は-14から14の範囲でなければならないと言う制約があるものと推測する。

AndroidとiOSの仕様差を吸収するため、daysSinceOnsetOfSymptoms必ずサーバーに送るようにする。サンプルアプリでは症状発生日の入力項目を設けていないので、取得できたTEKに適切な数値を設定して対応とする。

[Android] ServiceStateUpdatedのハンドリングを検討

現在はServiceStateUpdatedのBroadcastをハンドリングしていない。

これは各アプリでもBroadcastReceiverを持つことでハンドリングできるが、統合性を考えるとCappuccinoでハンドリングする方がよいか検討する(iOSで同種の処理は存在する?)。

ExposureNotificationClientをMock化できない

ExposureNotificationClientをインスタンス化するタイミングでENManagerもインスタンス化しているが、接触確認APIを使える状態にない(Entitlements.plistがない。権限がない)は強制終了する。

Mockに置き換え出来るようにするために、ENManagerのインスタンス化は遅延する必要がある。

[Sample] サーバー設定を外部ファイル化する

現在は定数ファイルConstants.csでビルド時に決定しているが、これをJSONのファイルとして保存して、再ビルドなしにカスタマイズできるようにしたい。

Close条件

  • コードを変更する

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.