Skip to content

Commit

Permalink
Add initial Exposure Notification API implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mar-v-in committed Aug 3, 2020
1 parent af28a78 commit 5f70d94
Show file tree
Hide file tree
Showing 92 changed files with 4,921 additions and 19 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 4 additions & 0 deletions play-services-core-proto/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ wire {
compileKotlin {
kotlinOptions.jvmTarget = 1.8
}

compileTestKotlin {
kotlinOptions.jvmTarget = 1.8
}
2 changes: 2 additions & 0 deletions play-services-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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')
Expand Down
13 changes: 12 additions & 1 deletion play-services-core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@
android:name="android.permission.UPDATE_APP_OPS_STATS"
tools:ignore="ProtectedPermissions" />

<uses-sdk tools:overrideLibrary="com.db.williamchart" />

<application
android:name="androidx.multidex.MultiDexApplication"
android:allowBackup="false"
Expand Down Expand Up @@ -419,6 +421,15 @@

<!-- microG custom UI -->

<activity
android:name="org.microg.gms.ui.ExposureNotificationsConfirmActivity"
android:exported="false"
android:theme="@style/Theme.AppCompat.DayNight.Dialog.Alert.NoActionBar">
<intent-filter>
<action android:name="org.microg.gms.nearby.exposurenotification.CONFIRM" />
</intent-filter>
</activity>

<!-- microG Settings shown in Launcher -->
<activity
android:name="org.microg.gms.ui.SettingsActivity"
Expand All @@ -427,11 +438,11 @@
android:roundIcon="@mipmap/ic_microg_settings">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
<action android:name="com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -11,6 +13,8 @@

import com.google.android.gms.R;

import org.microg.gms.nearby.exposurenotification.Constants;

public class SettingsActivity extends AppCompatActivity {
private AppBarConfiguration appBarConfiguration;

Expand All @@ -21,6 +25,12 @@ private NavController getNavController() {
@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();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.microg.gms.ui;

import android.os.Build;
import android.os.Bundle;

import androidx.annotation.Nullable;
Expand All @@ -10,6 +11,7 @@
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;

Expand All @@ -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;
Expand Down Expand Up @@ -86,6 +89,20 @@ private void updateDetails() {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String, Float> = 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)
}

}
Original file line number Diff line number Diff line change
@@ -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()
}
Original file line number Diff line number Diff line change
@@ -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()
}
}
}
Loading

0 comments on commit 5f70d94

Please sign in to comment.