Fix ANR-like bug when resuming MainActivity.

This commit is contained in:
Cody Henthorne
2023-08-17 15:02:16 -04:00
committed by GitHub
parent 74d5faf3fa
commit 39c1c1e371
5 changed files with 101 additions and 17 deletions

View File

@@ -1,10 +1,10 @@
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
@@ -16,6 +16,7 @@ import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.concurrent.LifecycleDisposable;
import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment; import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment;
import org.thoughtcrime.securesms.components.PromptBatterySaverDialogFragment; import org.thoughtcrime.securesms.components.PromptBatterySaverDialogFragment;
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController; import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
@@ -24,8 +25,7 @@ import org.thoughtcrime.securesms.conversationlist.RelinkDevicesReminderBottomSh
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceExitActivity; import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceExitActivity;
import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor; import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor;
import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.notifications.SlowNotificationsViewModel;
import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics;
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository; import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository;
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel; import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel;
import org.thoughtcrime.securesms.util.AppStartup; import org.thoughtcrime.securesms.util.AppStartup;
@@ -33,7 +33,6 @@ import org.thoughtcrime.securesms.util.CachedInflater;
import org.thoughtcrime.securesms.util.CommunicationActions; import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.PowerManagerCompat;
import org.thoughtcrime.securesms.util.SplashScreenUtil; import org.thoughtcrime.securesms.util.SplashScreenUtil;
import org.thoughtcrime.securesms.util.WindowUtil; import org.thoughtcrime.securesms.util.WindowUtil;
@@ -46,6 +45,9 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
private VoiceNoteMediaController mediaController; private VoiceNoteMediaController mediaController;
private ConversationListTabsViewModel conversationListTabsViewModel; private ConversationListTabsViewModel conversationListTabsViewModel;
private SlowNotificationsViewModel slowNotificationsViewModel;
private final LifecycleDisposable lifecycleDisposable = new LifecycleDisposable();
private boolean onFirstRender = false; private boolean onFirstRender = false;
@@ -80,6 +82,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
} }
}); });
lifecycleDisposable.bindTo(this);
mediaController = new VoiceNoteMediaController(this, true); mediaController = new VoiceNoteMediaController(this, true);
@@ -95,6 +98,28 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
conversationListTabsViewModel = new ViewModelProvider(this, factory).get(ConversationListTabsViewModel.class); conversationListTabsViewModel = new ViewModelProvider(this, factory).get(ConversationListTabsViewModel.class);
updateTabVisibility(); updateTabVisibility();
slowNotificationsViewModel = new ViewModelProvider(this).get(SlowNotificationsViewModel.class);
lifecycleDisposable.add(
slowNotificationsViewModel
.getSlowNotificationState()
.subscribe(this::presentSlowNotificationState)
);
}
@SuppressLint("NewApi")
private void presentSlowNotificationState(SlowNotificationsViewModel.State slowNotificationState) {
switch (slowNotificationState) {
case NONE:
break;
case PROMPT_BATTERY_SAVER_DIALOG:
PromptBatterySaverDialogFragment.show(getSupportFragmentManager());
break;
case PROMPT_DEBUGLOGS:
DebugLogsPromptDialogFragment.show(this, getSupportFragmentManager());
break;
}
} }
@Override @Override
@@ -143,15 +168,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
updateTabVisibility(); updateTabVisibility();
if (SlowNotificationHeuristics.isHavingDelayedNotifications()) { slowNotificationsViewModel.checkSlowNotificationHeuristics();
if (SlowNotificationHeuristics.isPotentiallyCausedByBatteryOptimizations() && Build.VERSION.SDK_INT >= 23) {
if (SlowNotificationHeuristics.shouldPromptBatterySaver()) {
PromptBatterySaverDialogFragment.show(this, getSupportFragmentManager());
}
} else if (SlowNotificationHeuristics.shouldPromptUserForLogs()) {
DebugLogsPromptDialogFragment.show(this, getSupportFragmentManager());
}
}
} }
@Override @Override

View File

@@ -5,7 +5,6 @@
package org.thoughtcrime.securesms.components package org.thoughtcrime.securesms.components
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -27,7 +26,7 @@ class PromptBatterySaverDialogFragment : FixedRoundedCornerBottomSheetDialogFrag
companion object { companion object {
@JvmStatic @JvmStatic
fun show(context: Context, fragmentManager: FragmentManager) { fun show(fragmentManager: FragmentManager) {
if (fragmentManager.findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) == null) { if (fragmentManager.findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) == null) {
PromptBatterySaverDialogFragment().apply { PromptBatterySaverDialogFragment().apply {
arguments = bundleOf() arguments = bundleOf()

View File

@@ -190,7 +190,7 @@ class NotificationsSettingsFragment : DSLSettingsFragment(R.string.preferences__
title = DSLSettingsText.from(R.string.preferences_notifications__troubleshoot), title = DSLSettingsText.from(R.string.preferences_notifications__troubleshoot),
isEnabled = true, isEnabled = true,
onClick = { onClick = {
PromptBatterySaverDialogFragment.show(requireContext(), childFragmentManager) PromptBatterySaverDialogFragment.show(childFragmentManager)
} }
) )
} }

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.notifications
import android.os.Build
import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.BehaviorSubject
import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics.isHavingDelayedNotifications
import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics.isPotentiallyCausedByBatteryOptimizations
import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics.shouldPromptBatterySaver
import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics.shouldPromptUserForLogs
import java.util.concurrent.TimeUnit
/**
* View model for checking for slow notifications and if we should prompt the user with help or for information.
*/
class SlowNotificationsViewModel : ViewModel() {
private val checkSubject = BehaviorSubject.create<Unit>()
val slowNotificationState: Observable<State>
init {
slowNotificationState = checkSubject
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.throttleFirst(1, TimeUnit.MINUTES)
.switchMapSingle {
checkHeuristics()
}
.distinctUntilChanged()
.observeOn(AndroidSchedulers.mainThread())
}
fun checkSlowNotificationHeuristics() {
checkSubject.onNext(Unit)
}
private fun checkHeuristics(): Single<State> {
return Single.fromCallable {
var state = State.NONE
if (isHavingDelayedNotifications()) {
if (isPotentiallyCausedByBatteryOptimizations() && Build.VERSION.SDK_INT >= 23) {
if (shouldPromptBatterySaver()) {
state = State.PROMPT_BATTERY_SAVER_DIALOG
}
} else if (shouldPromptUserForLogs()) {
state = State.PROMPT_DEBUGLOGS
}
}
return@fromCallable state
}.subscribeOn(Schedulers.io())
}
enum class State {
NONE,
PROMPT_BATTERY_SAVER_DIALOG,
PROMPT_DEBUGLOGS
}
}

View File

@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx4g -Xms256m -XX:MaxMetaspaceSize=1g org.gradle.jvmargs=-Xmx6g -Xms256m -XX:MaxMetaspaceSize=1g
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
kapt.incremental.apt=false kapt.incremental.apt=false