From 31a350eea70ede920002e310c2506a14e5648da4 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 27 Jul 2022 16:36:16 +0200 Subject: [PATCH 1/6] Enabling leakcanary on debug builds --- dependencies_groups.gradle | 2 ++ vector/build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index f60a77a92d..1c0135ae0f 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -106,7 +106,9 @@ ext.groups = [ 'com.pinterest.ktlint', 'com.posthog.android', 'com.squareup', + 'com.squareup.curtains', 'com.squareup.duktape', + 'com.squareup.leakcanary', 'com.squareup.moshi', 'com.squareup.okhttp3', 'com.squareup.okio', diff --git a/vector/build.gradle b/vector/build.gradle index 1244a84bfd..ee08ad7ae5 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -573,7 +573,7 @@ dependencies { debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0" // Activate when you want to check for leaks, from time to time. - //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' androidTestImplementation libs.androidx.testCore androidTestImplementation libs.androidx.testRunner From 36c69a46fdb9d3f9880b3890b779125d045eca04 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 8 Aug 2022 17:52:58 +0200 Subject: [PATCH 2/6] Adding way to enable leak canary at runtime --- .../vector/app/leakcanary/LeakCanaryProxy.kt | 26 ++++++++++++++++++ .../java/im/vector/app/VectorApplication.kt | 9 +++++++ .../im/vector/app/core/di/FragmentModule.kt | 6 +++++ .../features/settings/VectorPreferences.kt | 6 +++++ .../VectorSettingsAdvancedSettingsFragment.kt | 19 ++++++++++++- vector/src/main/res/values/strings.xml | 3 +++ .../xml/vector_settings_advanced_settings.xml | 9 ++++++- .../vector/app/leakcanary/LeakCanaryProxy.kt | 27 +++++++++++++++++++ 8 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt create mode 100644 vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt diff --git a/vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt b/vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt new file mode 100644 index 0000000000..3154c2c04b --- /dev/null +++ b/vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.leakcanary + +import leakcanary.LeakCanary +import javax.inject.Inject + +class LeakCanaryProxy @Inject constructor() { + fun enable(enable: Boolean) { + LeakCanary.config = LeakCanary.config.copy(dumpHeap = enable) + } +} diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 53222ab962..bbff8f35c8 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -61,6 +61,8 @@ import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.version.VersionProvider +import im.vector.app.leakcanary.LeakCanaryProxy +import im.vector.app.push.fcm.FcmHelper import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.AuthenticationService @@ -102,6 +104,7 @@ class VectorApplication : @Inject lateinit var matrix: Matrix @Inject lateinit var fcmHelper: FcmHelper @Inject lateinit var buildMeta: BuildMeta + @Inject lateinit var leakCanaryProxy: LeakCanaryProxy // font thread handler private var fontThreadHandler: Handler? = null @@ -196,6 +199,8 @@ class VectorApplication : // Initialize Mapbox before inflating mapViews Mapbox.getInstance(this) + + initMemoryLeakAnalysis() } private fun enableStrictModeIfNeeded() { @@ -251,4 +256,8 @@ class VectorApplication : handlerThread.start() return Handler(handlerThread.looper) } + + private fun initMemoryLeakAnalysis() { + leakCanaryProxy.enable(vectorPreferences.isMemoryLeakAnalysisEnabled()) + } } diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index e86b350534..36b1d994c1 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -150,6 +150,7 @@ import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRul import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment +import im.vector.app.features.settings.VectorSettingsAdvancedSettingsFragment import im.vector.app.features.settings.VectorSettingsGeneralFragment import im.vector.app.features.settings.VectorSettingsHelpAboutFragment import im.vector.app.features.settings.VectorSettingsLabsFragment @@ -624,6 +625,11 @@ interface FragmentModule { @FragmentKey(VectorSettingsSecurityPrivacyFragment::class) fun bindVectorSettingsSecurityPrivacyFragment(fragment: VectorSettingsSecurityPrivacyFragment): Fragment + @Binds + @IntoMap + @FragmentKey(VectorSettingsAdvancedSettingsFragment::class) + fun bindVectorSettingsAdvancedSettingsFragment(fragment: VectorSettingsAdvancedSettingsFragment): Fragment + @Binds @IntoMap @FragmentKey(VectorSettingsHelpAboutFragment::class) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index ac14bfc3c7..287b2c64ee 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -168,6 +168,7 @@ class VectorPreferences @Inject constructor( private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY" private const val SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY" private const val SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY = "SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY" + const val SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY = "SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY" const val SETTINGS_LABS_MSC3061_SHARE_KEYS_HISTORY = "SETTINGS_LABS_MSC3061_SHARE_KEYS_HISTORY" @@ -268,6 +269,7 @@ class VectorPreferences @Inject constructor( SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY, SETTINGS_LABS_ALLOW_EXTENDED_LOGS, SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY, + SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY, SETTINGS_USE_RAGE_SHAKE_KEY, SETTINGS_SECURITY_USE_FLAG_SECURE, @@ -368,6 +370,10 @@ class VectorPreferences @Inject constructor( return buildMeta.isDebug || (developerMode() && defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY, false)) } + fun isMemoryLeakAnalysisEnabled(): Boolean { + return buildMeta.isDebug && developerMode() && defaultPrefs.getBoolean(SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY, false) + } + fun didAskUserToEnableSessionPush(): Boolean { return defaultPrefs.getBoolean(DID_ASK_TO_ENABLE_SESSION_PUSH, false) } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt index b616ce1e1f..1bb7718390 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt @@ -19,14 +19,19 @@ package im.vector.app.features.settings import android.os.Bundle import androidx.preference.Preference import androidx.preference.SeekBarPreference +import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.preference.VectorPreferenceCategory import im.vector.app.core.preference.VectorSwitchPreference import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.rageshake.RageShake +import im.vector.app.leakcanary.LeakCanaryProxy +import javax.inject.Inject -class VectorSettingsAdvancedSettingsFragment : VectorSettingsBaseFragment() { +class VectorSettingsAdvancedSettingsFragment @Inject constructor( + private val leakCanaryProxy: LeakCanaryProxy, +) : VectorSettingsBaseFragment() { override var titleRes = R.string.settings_advanced_settings override val preferenceXmlRes = R.xml.vector_settings_advanced_settings @@ -82,5 +87,17 @@ class VectorSettingsAdvancedSettingsFragment : VectorSettingsBaseFragment() { } else { findPreference("SETTINGS_RAGE_SHAKE_CATEGORY_KEY")!!.isVisible = false } + + bindMemoryLeakSetting() + } + + private fun bindMemoryLeakSetting() { + findPreference(VectorPreferences.SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY)?.let { pref -> + pref.isVisible = BuildConfig.DEBUG + pref.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + leakCanaryProxy.enable(newValue as? Boolean ?: false) + true + } + } } } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index d1b2d237d9..1b21642e04 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2185,6 +2185,9 @@ ${app_name} may crash more often when an unexpected error occurs + Enable memory leak analysis + App performances may be impacted when enabled. + Show debug info on screen Show some useful info to help debugging the application diff --git a/vector/src/main/res/xml/vector_settings_advanced_settings.xml b/vector/src/main/res/xml/vector_settings_advanced_settings.xml index 2fb3fae310..c076fc2238 100644 --- a/vector/src/main/res/xml/vector_settings_advanced_settings.xml +++ b/vector/src/main/res/xml/vector_settings_advanced_settings.xml @@ -44,6 +44,13 @@ android:summary="@string/settings_developer_mode_fail_fast_summary" android:title="@string/settings_developer_mode_fail_fast_title" /> + + - \ No newline at end of file + diff --git a/vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt b/vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt new file mode 100644 index 0000000000..28c9f1c9d5 --- /dev/null +++ b/vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.leakcanary + +import javax.inject.Inject + +/** + * No op version. + */ +@Suppress("UNUSED_PARAMETER") +class LeakCanaryProxy @Inject constructor() { + fun enable(enable: Boolean) {} +} From 12405527e14b010123aa98977be515410ce583c5 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 9 Aug 2022 16:16:55 +0200 Subject: [PATCH 3/6] Adding changelog entry --- changelog.d/6786.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6786.misc diff --git a/changelog.d/6786.misc b/changelog.d/6786.misc new file mode 100644 index 0000000000..a916336ae4 --- /dev/null +++ b/changelog.d/6786.misc @@ -0,0 +1 @@ +Add a developer setting to enable LeakCanary at runtime From 250ee1faa1c4a7a9a0ff5aa866aa0f50570faac5 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 10 Aug 2022 14:19:03 +0200 Subject: [PATCH 4/6] Moving the new setting inside debug screen --- vector/src/debug/AndroidManifest.xml | 1 + .../app/features/debug/DebugMenuActivity.kt | 6 ++ .../debug/di/MavericksViewModelDebugModule.kt | 7 ++ .../debug/leak/DebugMemoryLeaksActivity.kt | 37 ++++++++++ .../debug/leak/DebugMemoryLeaksFragment.kt | 54 +++++++++++++++ .../debug/leak/DebugMemoryLeaksViewActions.kt | 23 +++++++ .../debug/leak/DebugMemoryLeaksViewModel.kt | 67 +++++++++++++++++++ .../debug/leak/DebugMemoryLeaksViewState.kt | 23 +++++++ .../debug/res/layout/activity_debug_menu.xml | 12 +++- .../layout/fragment_debug_memory_leaks.xml | 32 +++++++++ .../im/vector/app/core/di/FragmentModule.kt | 6 -- .../features/settings/VectorPreferences.kt | 9 ++- .../VectorSettingsAdvancedSettingsFragment.kt | 18 +---- vector/src/main/res/values/strings.xml | 3 - .../xml/vector_settings_advanced_settings.xml | 7 -- 15 files changed, 270 insertions(+), 35 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt create mode 100644 vector/src/debug/res/layout/fragment_debug_memory_leaks.xml diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml index 4ec47d4920..94fdb1b389 100644 --- a/vector/src/debug/AndroidManifest.xml +++ b/vector/src/debug/AndroidManifest.xml @@ -10,6 +10,7 @@ + () { views.debugAnalytics.setOnClickListener { startActivity(Intent(this, DebugAnalyticsActivity::class.java)) } + views.debugMemoryLeaks.setOnClickListener { openMemoryLeaksSettings() } views.debugTestTextViewLink.setOnClickListener { testTextViewLink() } views.debugOpenButtonStylesLight.setOnClickListener { startActivity(Intent(this, DebugVectorButtonStylesLightActivity::class.java)) @@ -130,6 +132,10 @@ class DebugMenuActivity : VectorBaseActivity() { startActivity(Intent(this, DebugPrivateSettingsActivity::class.java)) } + private fun openMemoryLeaksSettings() { + startActivity(Intent(this, DebugMemoryLeaksActivity::class.java)) + } + private fun renderQrCode(text: String) { views.debugQrCode.setData(text) } diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt index 6ef7fe441a..8512bb8c6d 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt @@ -24,6 +24,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksViewModelComponent import im.vector.app.core.di.MavericksViewModelKey import im.vector.app.features.debug.analytics.DebugAnalyticsViewModel +import im.vector.app.features.debug.leak.DebugMemoryLeaksViewModel import im.vector.app.features.debug.settings.DebugPrivateSettingsViewModel @InstallIn(MavericksViewModelComponent::class) @@ -39,4 +40,10 @@ interface MavericksViewModelDebugModule { @IntoMap @MavericksViewModelKey(DebugPrivateSettingsViewModel::class) fun debugPrivateSettingsViewModelFactory(factory: DebugPrivateSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + + @Binds + @IntoMap + @MavericksViewModelKey(DebugMemoryLeaksViewModel::class) + fun debugMemoryLeaksViewModelFactory(factory: DebugMemoryLeaksViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + } diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt new file mode 100644 index 0000000000..226c65e3ed --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.leak + +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.extensions.addFragment +import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding + +@AndroidEntryPoint +class DebugMemoryLeaksActivity : VectorBaseActivity() { + + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + + override fun initUiAndData() { + if (isFirstCreation()) { + addFragment( + views.simpleFragmentContainer, + DebugMemoryLeaksFragment::class.java + ) + } + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt new file mode 100644 index 0000000000..d3e70e26e6 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.leak + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.epoxy.onClick +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentDebugMemoryLeaksBinding + +@AndroidEntryPoint +class DebugMemoryLeaksFragment : VectorBaseFragment() { + + private val viewModel: DebugMemoryLeaksViewModel by fragmentViewModel() + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDebugMemoryLeaksBinding { + return FragmentDebugMemoryLeaksBinding.inflate(inflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setViewListeners() + } + + private fun setViewListeners() { + views.enableMemoryLeakAnalysis.onClick { + viewModel.handle(DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis(views.enableMemoryLeakAnalysis.isChecked)) + } + } + + override fun invalidate() = withState(viewModel) { viewState -> + views.enableMemoryLeakAnalysis.isChecked = viewState.isMemoryLeaksAnalysisEnabled + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt new file mode 100644 index 0000000000..e1447ae345 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.leak + +import im.vector.app.core.platform.VectorViewModelAction + +sealed interface DebugMemoryLeaksViewActions : VectorViewModelAction { + data class EnableMemoryLeaksAnalysis(val isEnabled: Boolean) : DebugMemoryLeaksViewActions +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt new file mode 100644 index 0000000000..617a6b2ecb --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.leak + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.settings.VectorPreferences +import im.vector.app.leakcanary.LeakCanaryProxy +import kotlinx.coroutines.launch + +class DebugMemoryLeaksViewModel @AssistedInject constructor( + @Assisted initialState: DebugMemoryLeaksViewState, + private val vectorPreferences: VectorPreferences, + private val leakCanaryProxy: LeakCanaryProxy, +) : VectorViewModel(initialState) { + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: DebugMemoryLeaksViewState): DebugMemoryLeaksViewModel + } + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + init { + viewModelScope.launch { + refreshStateFromPreferences() + } + } + + override fun handle(action: DebugMemoryLeaksViewActions) { + when (action) { + is DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis -> handleEnableMemoryLeaksAnalysis(action) + } + } + + private fun handleEnableMemoryLeaksAnalysis(action: DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis) { + viewModelScope.launch { + vectorPreferences.enableMemoryLeakAnalysis(action.isEnabled) + leakCanaryProxy.enable(action.isEnabled) + refreshStateFromPreferences() + } + } + + private fun refreshStateFromPreferences() { + setState { copy(isMemoryLeaksAnalysisEnabled = vectorPreferences.isMemoryLeakAnalysisEnabled()) } + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt new file mode 100644 index 0000000000..4e9fe4b402 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.leak + +import com.airbnb.mvrx.MavericksState + +data class DebugMemoryLeaksViewState( + val isMemoryLeaksAnalysisEnabled: Boolean = false +) : MavericksState diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index 8b38c17b35..b5efe0302c 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -1,5 +1,6 @@ + android:layout_height="wrap_content" + app:layout_anchor="@+id/scrollView2" + app:layout_anchorGravity="center"> +