0
0
mirror of https://github.com/thunderbird/thunderbird-android.git synced 2024-09-19 19:52:14 +02:00

Merge pull request #8130 from thunderbird/telemetry_setting

Add setting for app telemetry
This commit is contained in:
cketti 2024-09-10 15:24:57 +02:00 committed by GitHub
commit dc34b8f4a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 168 additions and 1 deletions

View File

@ -23,6 +23,7 @@ dependencies {
implementation(projects.feature.widget.messageList)
implementation(projects.feature.widget.shortcut)
implementation(projects.feature.widget.unread)
implementation(projects.feature.telemetry.api)
implementation(libs.androidx.work.runtime)

View File

@ -7,10 +7,12 @@ import app.k9mail.core.featureflag.FeatureFlagFactory
import app.k9mail.core.ui.theme.api.FeatureThemeProvider
import app.k9mail.core.ui.theme.api.ThemeProvider
import app.k9mail.dev.developmentModuleAdditions
import app.k9mail.feature.telemetry.api.TelemetryManager
import app.k9mail.feature.widget.shortcut.LauncherShortcutActivity
import app.k9mail.featureflag.K9FeatureFlagFactory
import app.k9mail.provider.K9AppNameProvider
import app.k9mail.provider.K9FeatureThemeProvider
import app.k9mail.telemetry.K9TelemetryManager
import app.k9mail.widget.appWidgetModule
import com.fsck.k9.AppConfig
import com.fsck.k9.BuildConfig
@ -33,6 +35,7 @@ val appModule = module {
single<ThemeProvider> { K9ThemeProvider() }
single<FeatureThemeProvider> { K9FeatureThemeProvider() }
single<FeatureFlagFactory> { K9FeatureFlagFactory() }
single<TelemetryManager> { K9TelemetryManager() }
developmentModuleAdditions()
}

View File

@ -0,0 +1,7 @@
package app.k9mail.telemetry
import app.k9mail.feature.telemetry.api.TelemetryManager
class K9TelemetryManager : TelemetryManager {
override fun isTelemetryFeatureIncluded(): Boolean = false
}

View File

@ -23,6 +23,7 @@ dependencies {
implementation(projects.feature.widget.messageList)
implementation(projects.feature.widget.shortcut)
implementation(projects.feature.widget.unread)
implementation(projects.feature.telemetry.glean)
implementation(libs.androidx.work.runtime)

View File

@ -5,6 +5,8 @@ import app.k9mail.core.common.provider.AppNameProvider
import app.k9mail.core.featureflag.FeatureFlagFactory
import app.k9mail.core.ui.theme.api.FeatureThemeProvider
import app.k9mail.core.ui.theme.api.ThemeProvider
import app.k9mail.feature.telemetry.api.TelemetryManager
import app.k9mail.feature.telemetry.glean.GleanTelemetryManager
import app.k9mail.feature.widget.shortcut.LauncherShortcutActivity
import com.fsck.k9.AppConfig
import com.fsck.k9.activity.MessageCompose
@ -32,6 +34,7 @@ val appModule = module {
single<ThemeProvider> { TbThemeProvider() }
single<FeatureThemeProvider> { TbFeatureThemeProvider() }
single<FeatureFlagFactory> { TbFeatureFlagFactory() }
single<TelemetryManager> { GleanTelemetryManager() }
developmentModuleAdditions()
}

View File

@ -0,0 +1,35 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24"
>
<path
android:fillColor="@android:color/white"
android:pathData="M19,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5C21,3.9 20.1,3 19,3zM19,19H5V5h14V19z"
/>
<path
android:fillColor="@android:color/white"
android:pathData="M7,12h2v5h-2z"
/>
<path
android:fillColor="@android:color/white"
android:pathData="M15,7h2v10h-2z"
/>
<path
android:fillColor="@android:color/white"
android:pathData="M11,14h2v3h-2z"
/>
<path
android:fillColor="@android:color/white"
android:pathData="M11,10h2v2h-2z"
/>
</vector>

View File

@ -0,0 +1,3 @@
plugins {
id(ThunderbirdPlugins.Library.jvm)
}

View File

@ -0,0 +1,8 @@
package app.k9mail.feature.telemetry.api
interface TelemetryManager {
/**
* Returns `true` if the app has a telemetry feature included.
*/
fun isTelemetryFeatureIncluded(): Boolean
}

View File

@ -0,0 +1,12 @@
plugins {
id(ThunderbirdPlugins.Library.android)
}
android {
namespace = "app.k9mail.feature.telemetry.glean"
resourcePrefix = "telemetry_glean_"
}
dependencies {
api(projects.feature.telemetry.api)
}

View File

@ -0,0 +1,7 @@
package app.k9mail.feature.telemetry.glean
import app.k9mail.feature.telemetry.api.TelemetryManager
class GleanTelemetryManager : TelemetryManager {
override fun isTelemetryFeatureIncluded(): Boolean = true
}

View File

@ -19,6 +19,7 @@ dependencies {
api(projects.legacy.search)
implementation(projects.plugins.openpgpApiLib.openpgpApi)
implementation(projects.feature.telemetry.api)
api(libs.androidx.annotation)

View File

@ -2,6 +2,7 @@ package com.fsck.k9
import android.content.Context
import android.content.SharedPreferences
import app.k9mail.feature.telemetry.api.TelemetryManager
import app.k9mail.legacy.account.Account
import app.k9mail.legacy.account.Account.SortType
import app.k9mail.legacy.di.DI
@ -20,6 +21,7 @@ import timber.log.Timber.DebugTree
// TODO "Use GeneralSettingsManager and GeneralSettings instead"
object K9 : EarlyInit {
private val generalSettingsManager: RealGeneralSettingsManager by inject()
private val telemetryManager: TelemetryManager by inject()
/**
* If this is `true`, various development settings will be enabled.
@ -267,6 +269,11 @@ object K9 : EarlyInit {
@JvmStatic
var swipeLeftAction: SwipeAction = SwipeAction.ToggleRead
// TODO: This is a feature-specific setting that doesn't need to be available to apps that don't include the
// feature. Extract `Storage` and `StorageEditor` to a separate module so feature modules can retrieve and store
// their own settings.
var isTelemetryEnabled = false
val isQuietTime: Boolean
get() {
if (!isQuietTimeEnabled) {
@ -384,6 +391,10 @@ object K9 : EarlyInit {
swipeRightAction = storage.getEnum("swipeRightAction", SwipeAction.ToggleSelection)
swipeLeftAction = storage.getEnum("swipeLeftAction", SwipeAction.ToggleRead)
if (telemetryManager.isTelemetryFeatureIncluded()) {
isTelemetryEnabled = storage.getBoolean("enableTelemetry", true)
}
}
internal fun save(editor: StorageEditor) {
@ -448,6 +459,10 @@ object K9 : EarlyInit {
editor.putEnum("swipeRightAction", swipeRightAction)
editor.putEnum("swipeLeftAction", swipeLeftAction)
if (telemetryManager.isTelemetryFeatureIncluded()) {
editor.putBoolean("enableTelemetry", isTelemetryEnabled)
}
fontSizes.save(editor)
}

View File

@ -9,6 +9,7 @@ import java.util.TreeMap;
import android.content.Context;
import app.k9mail.feature.telemetry.api.TelemetryManager;
import app.k9mail.legacy.account.Account;
import app.k9mail.legacy.account.Account.SortType;
import app.k9mail.legacy.di.DI;
@ -48,6 +49,8 @@ class GeneralSettingsDescriptions {
static final Map<String, TreeMap<Integer, SettingsDescription<?>>> SETTINGS;
private static final Map<Integer, SettingsUpgrader> UPGRADERS;
private static final TelemetryManager telemetryManager = DI.get(TelemetryManager.class);
static {
Map<String, TreeMap<Integer, SettingsDescription<?>>> s = new LinkedHashMap<>();
@ -298,6 +301,13 @@ class GeneralSettingsDescriptions {
new EnumSetting<>(PostMarkAsUnreadNavigation.class, PostMarkAsUnreadNavigation.ReturnToMessageList))
));
// TODO: Add a way to properly support feature-specific settings.
if (telemetryManager.isTelemetryFeatureIncluded()) {
s.put("enableTelemetry", Settings.versions(
new V(97, new BooleanSetting(true))
));
}
SETTINGS = Collections.unmodifiableMap(s);
Map<Integer, SettingsUpgrader> u = new HashMap<>();

View File

@ -33,7 +33,7 @@ class Settings {
*
* @see SettingsExporter
*/
public static final int VERSION = 96;
public static final int VERSION = 97;
static Map<String, Object> validate(int version, Map<String, TreeMap<Integer, SettingsDescription<?>>> settings,
Map<String, String> importedSettings, boolean useDefaultValues) {

View File

@ -2,6 +2,7 @@ package com.fsck.k9
import android.app.Application
import androidx.work.WorkManager
import app.k9mail.feature.telemetry.api.TelemetryManager
import app.k9mail.legacy.di.DI
import com.fsck.k9.backend.BackendManager
import com.fsck.k9.controller.ControllerExtension
@ -43,4 +44,9 @@ val testModule = module {
single { mock<NotificationStrategy>() }
single(named("controllerExtensions")) { emptyList<ControllerExtension>() }
single { mock<WorkManager>() }
single<TelemetryManager> {
object : TelemetryManager {
override fun isTelemetryFeatureIncluded(): Boolean = true
}
}
}

View File

@ -14,6 +14,7 @@ dependencies {
testImplementation(projects.mail.testing)
testImplementation(projects.legacy.testing)
testImplementation(projects.feature.telemetry.api)
testImplementation(libs.robolectric)
testImplementation(libs.commons.io)
}

View File

@ -1,6 +1,7 @@
package com.fsck.k9.storage
import android.app.Application
import app.k9mail.feature.telemetry.api.TelemetryManager
import app.k9mail.legacy.di.DI
import com.fsck.k9.AppConfig
import com.fsck.k9.Core
@ -32,4 +33,9 @@ val testModule = module {
single { mock<EncryptionExtractor>() }
single<StoragePersister> { K9StoragePersister(get()) }
single { mock<BackendManager>() }
single<TelemetryManager> {
object : TelemetryManager {
override fun isTelemetryFeatureIncluded(): Boolean = true
}
}
}

View File

@ -19,6 +19,7 @@ dependencies {
// TODO: Remove AccountOauth dependency
implementation(projects.feature.account.oauth)
implementation(projects.feature.settings.import)
implementation(projects.feature.telemetry.api)
compileOnly(projects.mail.protocols.imap)

View File

@ -45,6 +45,7 @@ class GeneralSettingsDataStore(
"debug_logging" -> K9.isDebugLoggingEnabled
"sensitive_logging" -> K9.isSensitiveDebugLoggingEnabled
"volume_navigation" -> K9.isUseVolumeKeysForNavigation
"enable_telemetry" -> K9.isTelemetryEnabled
else -> defValue
}
}
@ -74,6 +75,7 @@ class GeneralSettingsDataStore(
"debug_logging" -> K9.isDebugLoggingEnabled = value
"sensitive_logging" -> K9.isSensitiveDebugLoggingEnabled = value
"volume_navigation" -> K9.isUseVolumeKeysForNavigation = value
"enable_telemetry" -> K9.isTelemetryEnabled = value
else -> return
}

View File

@ -7,9 +7,12 @@ import android.view.MenuInflater
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.preference.ListPreference
import androidx.preference.Preference
import app.k9mail.feature.telemetry.api.TelemetryManager
import com.fsck.k9.ui.R
import com.fsck.k9.ui.base.extensions.withArguments
import com.fsck.k9.ui.observe
import com.fsck.k9.ui.settings.remove
import com.google.android.material.snackbar.Snackbar
import com.takisoft.preferencex.PreferenceFragmentCompat
import org.koin.android.ext.android.inject
@ -19,6 +22,7 @@ import com.fsck.k9.core.R as CoreR
class GeneralSettingsFragment : PreferenceFragmentCompat() {
private val viewModel: GeneralSettingsViewModel by viewModel()
private val dataStore: GeneralSettingsDataStore by inject()
private val telemetryManager: TelemetryManager by inject()
private var rootKey: String? = null
private var currentUiState: GeneralSettingsUiState? = null
@ -37,6 +41,7 @@ class GeneralSettingsFragment : PreferenceFragmentCompat() {
setPreferencesFromResource(R.xml.general_settings, rootKey)
initializeTheme()
initializeDataCollection()
viewModel.uiState.observe(this) { uiState ->
updateUiState(uiState)
@ -80,6 +85,12 @@ class GeneralSettingsFragment : PreferenceFragmentCompat() {
}
}
private fun initializeDataCollection() {
if (!telemetryManager.isTelemetryFeatureIncluded()) {
findPreference<Preference>(PREFERENCE_DATA_COLLECTION)?.remove()
}
}
private fun updateUiState(uiState: GeneralSettingsUiState) {
val oldUiState = currentUiState
currentUiState = uiState
@ -119,6 +130,7 @@ class GeneralSettingsFragment : PreferenceFragmentCompat() {
companion object {
private const val PREFERENCE_THEME = "theme"
private const val PREFERENCE_SCREEN_DEBUGGING = "debug_preferences"
private const val PREFERENCE_DATA_COLLECTION = "data_collection"
fun create(rootKey: String? = null) = GeneralSettingsFragment().withArguments(ARG_PREFERENCE_ROOT to rootKey)
}

View File

@ -1114,4 +1114,11 @@ You can keep this message and use it as a backup for your secret key. If you wan
<!-- For unread messages the first line of a message list item is modified by this to improve the experience for people with screen readers. -->
<string name="message_list_content_description_unread_prefix">unread, %s</string>
<!-- Name of the "data collection" section in the general settings screen -->
<string name="settings_ui_data_collection">Data collection</string>
<!-- Title of the "Usage and technical data" setting used in the "data collection" section of the general settings screen -->
<string name="settings_ui_telemetry_title">Usage and technical data</string>
<!-- Description of the "Usage and technical data" setting used in the "data collection" section of the general settings screen -->
<string name="settings_ui_telemetry_description">Shares performance, usage, hardware and customization data about this app with Mozilla to help us make Thunderbird better</string>
</resources>

View File

@ -514,6 +514,21 @@
</PreferenceScreen>
<PreferenceScreen
android:icon="@drawable/ic_analytics"
android:key="data_collection"
android:title="@string/settings_ui_data_collection"
search:ignore="true"
>
<SwitchPreference
android:key="enable_telemetry"
android:summary="@string/settings_ui_telemetry_description"
android:title="@string/settings_ui_telemetry_title"
/>
</PreferenceScreen>
<PreferenceScreen
android:icon="@drawable/ic_bug_report"
android:key="debug_preferences"

View File

@ -1,6 +1,7 @@
package com.fsck.k9
import android.app.Application
import app.k9mail.feature.telemetry.api.TelemetryManager
import app.k9mail.legacy.di.DI
import com.fsck.k9.preferences.InMemoryStoragePersister
import com.fsck.k9.preferences.StoragePersister
@ -26,4 +27,9 @@ val testModule = module {
single { AppConfig(emptyList()) }
single<CoreResourceProvider> { TestCoreResourceProvider() }
single<StoragePersister> { InMemoryStoragePersister() }
single<TelemetryManager> {
object : TelemetryManager {
override fun isTelemetryFeatureIncluded(): Boolean = true
}
}
}

View File

@ -75,6 +75,11 @@ include(
":feature:migration:provider",
)
include(
":feature:telemetry:api",
":feature:telemetry:glean",
)
include(
":core:common",
":core:featureflags",