From 5f70d943cbceabcd9d2c72f8460ea58cba7e08fb Mon Sep 17 00:00:00 2001 From: Marvin W Date: Mon, 3 Aug 2020 18:07:06 +0200 Subject: [PATCH] Add initial Exposure Notification API implementation --- build.gradle | 1 + play-services-core-proto/build.gradle | 4 + play-services-core/build.gradle | 2 + .../src/main/AndroidManifest.xml | 13 +- .../org/microg/gms/ui/SettingsActivity.java | 10 + .../org/microg/gms/ui/SettingsFragment.java | 17 + .../org/microg/gms/ui/AppIconPreference.kt | 12 +- .../org/microg/gms/ui/BarChartPreference.kt | 58 ++ .../ui/ExposureNotificationsAppFragment.kt | 57 + ...sureNotificationsAppPreferencesFragment.kt | 60 ++ .../ExposureNotificationsConfirmActivity.kt | 68 ++ .../gms/ui/ExposureNotificationsFragment.kt | 38 + ...xposureNotificationsPreferencesFragment.kt | 119 +++ .../ui/ExposureNotificationsRpisFragment.kt | 75 ++ .../gms/ui/PushNotificationAppFragment.kt | 2 +- .../org/microg/gms/ui/TextPreference.kt | 35 + .../src/main/res/drawable/ic_check_list.xml | 18 + .../src/main/res/drawable/ic_open.xml | 17 + .../main/res/drawable/ic_virus_outline.xml | 16 + .../layout/device_registration_fragment.xml | 2 +- .../exposure_notifications_app_fragment.xml | 82 ++ ...xposure_notifications_confirm_activity.xml | 56 + .../exposure_notifications_fragment.xml | 41 + .../main/res/layout/preference_bar_chart.xml | 18 + .../res/layout/push_notification_fragment.xml | 2 +- .../main/res/layout/safety_net_fragment.xml | 2 +- .../src/main/res/navigation/nav_settings.xml | 53 +- .../src/main/res/values/strings.xml | 39 + .../src/main/res/values/themes.xml | 5 + .../xml/preferences_device_registration.xml | 2 +- .../preferences_exposure_notifications.xml | 45 + ...preferences_exposure_notifications_app.xml | 21 + ...references_exposure_notifications_rpis.xml | 28 + .../xml/preferences_push_notifications.xml | 5 +- .../main/res/xml/preferences_safetynet.xml | 2 +- .../src/main/res/xml/preferences_start.xml | 4 + play-services-nearby-api/build.gradle | 28 + .../src/main/AndroidManifest.xml | 6 + .../ExposureInformation.aidl | 8 + .../exposurenotification/ExposureSummary.aidl | 8 + .../TemporaryExposureKey.aidl | 8 + .../GetExposureInformationParams.aidl | 8 + .../internal/GetExposureSummaryParams.aidl | 8 + .../GetTemporaryExposureKeyHistoryParams.aidl | 8 + .../internal/IBooleanCallback.aidl | 12 + .../IExposureInformationListCallback.aidl | 13 + .../internal/IExposureSummaryCallback.aidl | 13 + .../INearbyExposureNotificationService.aidl | 25 + .../ITemporaryExposureKeyListCallback.aidl | 13 + .../internal/IsEnabledParams.aidl | 8 + .../internal/ProvideDiagnosisKeysParams.aidl | 8 + .../internal/StartParams.aidl | 8 + .../internal/StopParams.aidl | 8 + .../ExposureConfiguration.java | 208 ++++ .../ExposureInformation.java | 152 +++ .../ExposureNotificationStatusCodes.java | 43 + .../exposurenotification/ExposureSummary.java | 128 +++ .../exposurenotification/RiskLevel.java | 18 + .../TemporaryExposureKey.java | 115 +++ .../GetExposureInformationParams.java | 24 + .../internal/GetExposureSummaryParams.java | 24 + .../GetTemporaryExposureKeyHistoryParams.java | 21 + .../internal/IsEnabledParams.java | 22 + .../internal/ProvideDiagnosisKeysParams.java | 31 + .../internal/StartParams.java | 27 + .../internal/StopParams.java | 24 + .../exposurenotification/Constants.java | 14 + play-services-nearby-core-proto/build.gradle | 23 + .../main/proto/TemporaryExposureKeyFile.proto | 95 ++ play-services-nearby-core/build.gradle | 50 + .../src/main/AndroidManifest.xml | 42 + .../exposurenotification/AdvertiserService.kt | 101 ++ .../nearby/exposurenotification/Constants.kt | 29 + .../gms/nearby/exposurenotification/Crypto.kt | 120 +++ .../nearby/exposurenotification/DeviceInfo.kt | 12 + .../exposurenotification/ExposureDatabase.kt | 447 ++++++++ .../ExposureNotificationService.kt | 57 + .../ExposureNotificationServiceImpl.kt | 278 +++++ .../ExposurePreferences.kt | 35 + .../exposurenotification/MeasuredExposure.kt | 102 ++ .../exposurenotification/ScannerService.kt | 67 ++ .../exposurenotification/ServiceTrigger.kt | 24 + .../exposurenotification/CryptoTest.java | 65 ++ .../exposurenotification/TestVectors.java | 976 ++++++++++++++++++ play-services-nearby/build.gradle | 27 + .../src/main/AndroidManifest.xml | 6 + .../com/google/android/gms/nearby/Nearby.java | 20 + .../ExposureNotificationClient.java | 39 + .../nearby/ExposureNotificationApiClient.java | 64 ++ .../ExposureNotificationClientImpl.java | 179 ++++ play-services-wearable-proto/build.gradle | 4 + settings.gradle | 8 +- 92 files changed, 4921 insertions(+), 19 deletions(-) create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/BarChartPreference.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppFragment.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppPreferencesFragment.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsConfirmActivity.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsFragment.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsPreferencesFragment.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsRpisFragment.kt create mode 100644 play-services-core/src/main/kotlin/org/microg/gms/ui/TextPreference.kt create mode 100644 play-services-core/src/main/res/drawable/ic_check_list.xml create mode 100644 play-services-core/src/main/res/drawable/ic_open.xml create mode 100644 play-services-core/src/main/res/drawable/ic_virus_outline.xml create mode 100644 play-services-core/src/main/res/layout/exposure_notifications_app_fragment.xml create mode 100644 play-services-core/src/main/res/layout/exposure_notifications_confirm_activity.xml create mode 100644 play-services-core/src/main/res/layout/exposure_notifications_fragment.xml create mode 100644 play-services-core/src/main/res/layout/preference_bar_chart.xml create mode 100644 play-services-core/src/main/res/xml/preferences_exposure_notifications.xml create mode 100644 play-services-core/src/main/res/xml/preferences_exposure_notifications_app.xml create mode 100644 play-services-core/src/main/res/xml/preferences_exposure_notifications_rpis.xml create mode 100644 play-services-nearby-api/build.gradle create mode 100644 play-services-nearby-api/src/main/AndroidManifest.xml create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/ExposureInformation.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/ExposureSummary.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/TemporaryExposureKey.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetExposureInformationParams.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetExposureSummaryParams.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/GetTemporaryExposureKeyHistoryParams.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IBooleanCallback.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IExposureInformationListCallback.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IExposureSummaryCallback.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/INearbyExposureNotificationService.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/ITemporaryExposureKeyListCallback.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/IsEnabledParams.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/ProvideDiagnosisKeysParams.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/StartParams.aidl create mode 100644 play-services-nearby-api/src/main/aidl/com/google/android/gms/nearby/exposurenotification/internal/StopParams.aidl create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureConfiguration.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureInformation.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationStatusCodes.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureSummary.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/RiskLevel.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/TemporaryExposureKey.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetExposureInformationParams.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetExposureSummaryParams.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/GetTemporaryExposureKeyHistoryParams.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/IsEnabledParams.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/ProvideDiagnosisKeysParams.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/StartParams.java create mode 100644 play-services-nearby-api/src/main/java/com/google/android/gms/nearby/exposurenotification/internal/StopParams.java create mode 100644 play-services-nearby-api/src/main/java/org/microg/gms/nearby/exposurenotification/Constants.java create mode 100644 play-services-nearby-core-proto/build.gradle create mode 100644 play-services-nearby-core-proto/src/main/proto/TemporaryExposureKeyFile.proto create mode 100644 play-services-nearby-core/build.gradle create mode 100644 play-services-nearby-core/src/main/AndroidManifest.xml create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/AdvertiserService.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/Constants.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/Crypto.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/DeviceInfo.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureDatabase.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationService.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposureNotificationServiceImpl.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ExposurePreferences.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/MeasuredExposure.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ScannerService.kt create mode 100644 play-services-nearby-core/src/main/kotlin/org/microg/gms/nearby/exposurenotification/ServiceTrigger.kt create mode 100644 play-services-nearby-core/src/test/java/org/microg/gms/nearby/exposurenotification/CryptoTest.java create mode 100644 play-services-nearby-core/src/test/java/org/microg/gms/nearby/exposurenotification/TestVectors.java create mode 100644 play-services-nearby/build.gradle create mode 100644 play-services-nearby/src/main/AndroidManifest.xml create mode 100644 play-services-nearby/src/main/java/com/google/android/gms/nearby/Nearby.java create mode 100644 play-services-nearby/src/main/java/com/google/android/gms/nearby/exposurenotification/ExposureNotificationClient.java create mode 100644 play-services-nearby/src/main/java/org/microg/gms/nearby/ExposureNotificationApiClient.java create mode 100644 play-services-nearby/src/main/java/org/microg/gms/nearby/ExposureNotificationClientImpl.java diff --git a/build.gradle b/build.gradle index 9cdd3d2e..b3002c34 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,7 @@ buildscript { ext.annotationVersion = '1.1.0' ext.appcompatVersion = '1.1.0' + ext.coreVersion = '1.3.0' ext.fragmentVersion = '1.2.5' ext.lifecycleVersion = '2.2.0' ext.mediarouterVersion = '1.1.0' diff --git a/play-services-core-proto/build.gradle b/play-services-core-proto/build.gradle index 1e267ed2..3ae24b59 100644 --- a/play-services-core-proto/build.gradle +++ b/play-services-core-proto/build.gradle @@ -19,3 +19,7 @@ wire { compileKotlin { kotlinOptions.jvmTarget = 1.8 } + +compileTestKotlin { + kotlinOptions.jvmTarget = 1.8 +} diff --git a/play-services-core/build.gradle b/play-services-core/build.gradle index 523f1017..03a0b700 100644 --- a/play-services-core/build.gradle +++ b/play-services-core/build.gradle @@ -26,6 +26,7 @@ configurations { dependencies { implementation "com.squareup.wire:wire-runtime:$wireVersion" implementation "de.hdodenhof:circleimageview:1.3.0" + implementation "com.diogobernardino:williamchart:3.7.1" implementation "org.conscrypt:conscrypt-android:2.1.0" // TODO: Switch to upstream once raw requests are merged // https://github.com/vitalidze/chromecast-java-api-v2/pull/99 @@ -40,6 +41,7 @@ dependencies { implementation project(':firebase-dynamic-links-api') implementation project(':play-services-base-core') implementation project(':play-services-location-core') + implementation project(':play-services-nearby-core') implementation project(':play-services-core-proto') implementation project(':play-services-core:microg-ui-tools') // deprecated implementation project(':play-services-api') diff --git a/play-services-core/src/main/AndroidManifest.xml b/play-services-core/src/main/AndroidManifest.xml index e6353ae6..0b38be30 100644 --- a/play-services-core/src/main/AndroidManifest.xml +++ b/play-services-core/src/main/AndroidManifest.xml @@ -107,6 +107,8 @@ android:name="android.permission.UPDATE_APP_OPS_STATS" tools:ignore="ProtectedPermissions" /> + + + + + + + + - + diff --git a/play-services-core/src/main/java/org/microg/gms/ui/SettingsActivity.java b/play-services-core/src/main/java/org/microg/gms/ui/SettingsActivity.java index 05befb86..b98d7525 100644 --- a/play-services-core/src/main/java/org/microg/gms/ui/SettingsActivity.java +++ b/play-services-core/src/main/java/org/microg/gms/ui/SettingsActivity.java @@ -1,5 +1,7 @@ package org.microg.gms.ui; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import androidx.annotation.Nullable; @@ -11,6 +13,8 @@ import androidx.navigation.ui.NavigationUI; import com.google.android.gms.R; +import org.microg.gms.nearby.exposurenotification.Constants; + public class SettingsActivity extends AppCompatActivity { private AppBarConfiguration appBarConfiguration; @@ -21,6 +25,12 @@ public class SettingsActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (Constants.ACTION_EXPOSURE_NOTIFICATION_SETTINGS.equals(intent.getAction()) && intent.getData() == null) { + intent.setData(Uri.parse("x-gms-settings://exposure-notifications")); + } + setContentView(R.layout.settings_root_activity); appBarConfiguration = new AppBarConfiguration.Builder(getNavController().getGraph()).build(); diff --git a/play-services-core/src/main/java/org/microg/gms/ui/SettingsFragment.java b/play-services-core/src/main/java/org/microg/gms/ui/SettingsFragment.java index 482152e6..b8dba158 100644 --- a/play-services-core/src/main/java/org/microg/gms/ui/SettingsFragment.java +++ b/play-services-core/src/main/java/org/microg/gms/ui/SettingsFragment.java @@ -1,5 +1,6 @@ package org.microg.gms.ui; +import android.os.Build; import android.os.Bundle; import androidx.annotation.Nullable; @@ -10,6 +11,7 @@ import com.google.android.gms.R; import org.microg.gms.checkin.CheckinPrefs; import org.microg.gms.gcm.GcmDatabase; import org.microg.gms.gcm.GcmPrefs; +import org.microg.gms.nearby.exposurenotification.ExposurePreferences; import org.microg.gms.snet.SafetyNetPrefs; import org.microg.tools.ui.ResourceSettingsFragment; @@ -20,6 +22,7 @@ public class SettingsFragment extends ResourceSettingsFragment { public static final String PREF_SNET = "pref_snet"; public static final String PREF_UNIFIEDNLP = "pref_unifiednlp"; public static final String PREF_CHECKIN = "pref_checkin"; + public static final String PREF_EXPOSURE = "pref_exposure"; public SettingsFragment() { preferencesResource = R.xml.preferences_start; @@ -86,6 +89,20 @@ public class SettingsFragment extends ResourceSettingsFragment { NavHostFragment.findNavController(SettingsFragment.this).navigate(R.id.openUnifiedNlpSettings); return true; }); + if (Build.VERSION.SDK_INT >= 21) { + findPreference(PREF_EXPOSURE).setVisible(true); + if (new ExposurePreferences(getContext()).getScannerEnabled()) { + findPreference(PREF_EXPOSURE).setSummary(getString(R.string.service_status_enabled_short)); + } else { + findPreference(PREF_EXPOSURE).setSummary(R.string.service_status_disabled_short); + } + findPreference(PREF_EXPOSURE).setOnPreferenceClickListener(preference -> { + NavHostFragment.findNavController(SettingsFragment.this).navigate(R.id.openExposureNotificationSettings); + return true; + }); + } else { + findPreference(PREF_EXPOSURE).setVisible(false); + } boolean checkinEnabled = CheckinPrefs.get(getContext()).isEnabled(); findPreference(PREF_CHECKIN).setSummary(checkinEnabled ? R.string.service_status_enabled_short : R.string.service_status_disabled_short); diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt index 97bcca1d..4d53f241 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/AppIconPreference.kt @@ -6,15 +6,21 @@ package org.microg.gms.ui import android.content.Context +import android.util.AttributeSet import android.util.DisplayMetrics import android.widget.ImageView import androidx.preference.Preference import androidx.preference.PreferenceViewHolder -class AppIconPreference(context: Context) : Preference(context) { - override fun onBindViewHolder(holder: PreferenceViewHolder?) { +class AppIconPreference : Preference { + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context) : super(context) + + override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - val icon = holder?.findViewById(android.R.id.icon) + val icon = holder.findViewById(android.R.id.icon) if (icon is ImageView) { icon.adjustViewBounds = true icon.scaleType = ImageView.ScaleType.CENTER_INSIDE diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/BarChartPreference.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/BarChartPreference.kt new file mode 100644 index 00000000..368cf457 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/BarChartPreference.kt @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.ui + +import android.content.Context +import android.util.AttributeSet +import android.util.Log +import androidx.preference.Preference +import androidx.preference.PreferenceViewHolder +import com.db.williamchart.data.Scale +import com.db.williamchart.view.BarChartView +import com.google.android.gms.R + +class BarChartPreference : Preference { + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context?) : super(context) + + init { + layoutResource = R.layout.preference_bar_chart + } + + private lateinit var chart: BarChartView + var labelsFormatter: (Float) -> String = { it.toString() } + set(value) { + field = value + if (this::chart.isInitialized) { + chart.labelsFormatter = value + } + } + var scale: Scale? = null + set(value) { + field = value + if (value != null && this::chart.isInitialized) { + chart.scale = value + } + } + var data: LinkedHashMap = linkedMapOf() + set(value) { + field = value + if (this::chart.isInitialized) { + chart.animate(data) + } + } + + override fun onBindViewHolder(holder: PreferenceViewHolder) { + super.onBindViewHolder(holder) + chart = holder.itemView as? BarChartView ?: holder.findViewById(R.id.bar_chart) as BarChartView + chart.labelsFormatter = labelsFormatter + scale?.let { chart.scale = it } + chart.animate(data) + } + +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppFragment.kt new file mode 100644 index 00000000..bfa544ce --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppFragment.kt @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.ui + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.content.res.AppCompatResources +import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope +import com.google.android.gms.R +import com.google.android.gms.databinding.ExposureNotificationsAppFragmentBinding +import com.google.android.gms.databinding.ExposureNotificationsFragmentBinding +import org.microg.gms.nearby.exposurenotification.ExposurePreferences + +class ExposureNotificationsAppFragment : Fragment(R.layout.exposure_notifications_app_fragment) { + private lateinit var binding: ExposureNotificationsAppFragmentBinding + val packageName: String? + get() = arguments?.getString("package") + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + binding = ExposureNotificationsAppFragmentBinding.inflate(inflater, container, false) + binding.callbacks = object : ExposureNotificationsAppFragmentCallbacks { + override fun onAppClicked() { + val intent = Intent() + intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + val uri: Uri = Uri.fromParts("package", packageName, null) + intent.data = uri + context!!.startActivity(intent) + } + } + childFragmentManager.findFragmentById(R.id.sub_preferences)?.arguments = arguments + return binding.root + } + + override fun onResume() { + super.onResume() + lifecycleScope.launchWhenResumed { + val pm = requireContext().packageManager + val applicationInfo = pm.getApplicationInfoIfExists(packageName) + binding.appName = applicationInfo?.loadLabel(pm)?.toString() ?: packageName + binding.appIcon = applicationInfo?.loadIcon(pm) + ?: AppCompatResources.getDrawable(requireContext(), android.R.mipmap.sym_def_app_icon) + } + } +} + +interface ExposureNotificationsAppFragmentCallbacks { + fun onAppClicked() +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppPreferencesFragment.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppPreferencesFragment.kt new file mode 100644 index 00000000..2b1c7c55 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsAppPreferencesFragment.kt @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.ui + +import android.content.Intent +import android.os.Bundle +import android.text.format.DateUtils +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import com.google.android.gms.R +import org.microg.gms.nearby.exposurenotification.ExposureDatabase + +class ExposureNotificationsAppPreferencesFragment : PreferenceFragmentCompat() { + private lateinit var open: Preference + private lateinit var checks: Preference + private val packageName: String? + get() = arguments?.getString("package") + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.preferences_exposure_notifications_app) + } + + override fun onBindPreferences() { + open = preferenceScreen.findPreference("pref_exposure_app_open") ?: open + checks = preferenceScreen.findPreference("pref_exposure_app_checks") ?: checks + open.onPreferenceClickListener = Preference.OnPreferenceClickListener { + try { + packageName?.let { + context?.packageManager?.getLaunchIntentForPackage(it)?.let { intent -> + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context?.startActivity(intent) + } + } + } catch (ignored: Exception) { + } + true + } + } + + override fun onResume() { + super.onResume() + updateContent() + } + + fun updateContent() { + packageName?.let { packageName -> + val database = ExposureDatabase(requireContext()) + var str = getString(R.string.pref_exposure_app_checks_summary, database.countMethodCalls(packageName, "provideDiagnosisKeys")) + val lastCheckTime = database.lastMethodCall(packageName, "provideDiagnosisKeys") + if (lastCheckTime != null && lastCheckTime != 0L) { + str += "\n" + getString(R.string.pref_exposure_app_last_check_summary, DateUtils.getRelativeDateTimeString(context, lastCheckTime, DateUtils.MINUTE_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_SHOW_TIME)) + } + checks.summary = str + database.close() + } + } +} diff --git a/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsConfirmActivity.kt b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsConfirmActivity.kt new file mode 100644 index 00000000..3b2988c7 --- /dev/null +++ b/play-services-core/src/main/kotlin/org/microg/gms/ui/ExposureNotificationsConfirmActivity.kt @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2020, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.ui + +import android.os.Bundle +import android.os.ResultReceiver +import android.widget.Button +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import com.google.android.gms.R +import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.* +import org.microg.gms.nearby.exposurenotification.* + +class ExposureNotificationsConfirmActivity : AppCompatActivity() { + private var resultCode: Int = FAILED + private val resultData: Bundle = Bundle() + private val receiver: ResultReceiver? + get() = intent.getParcelableExtra(KEY_CONFIRM_RECEIVER) + private val action: String? + get() = intent.getStringExtra(KEY_CONFIRM_ACTION) + private val targetPackageName: String? + get() = intent.getStringExtra(KEY_CONFIRM_PACKAGE) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.exposure_notifications_confirm_activity) + val applicationInfo = packageManager.getApplicationInfoIfExists(targetPackageName) + when (action) { + CONFIRM_ACTION_START -> { + findViewById(android.R.id.title).text = getString(R.string.exposure_confirm_start_title) + findViewById(android.R.id.summary).text = getString(R.string.exposure_confirm_start_summary, applicationInfo?.loadLabel(packageManager) + ?: targetPackageName) + findViewById