mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 04:58:45 +00:00
Prompt user for debug logs with slow notifications.
This commit is contained in:
@@ -15,12 +15,14 @@ import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner;
|
||||
import org.thoughtcrime.securesms.conversationlist.RelinkDevicesReminderBottomSheetFragment;
|
||||
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceExitActivity;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.net.DeviceTransferBlockingInterceptor;
|
||||
import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics;
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabRepository;
|
||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel;
|
||||
import org.thoughtcrime.securesms.util.AppStartup;
|
||||
@@ -136,6 +138,10 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
||||
}
|
||||
|
||||
updateTabVisibility();
|
||||
|
||||
if (SlowNotificationHeuristics.shouldPromptUserForLogs()) {
|
||||
DebugLogsPromptDialogFragment.show(this, getSupportFragmentManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.signal.core.util.ResourceUtil
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.databinding.PromptLogsBottomSheetBinding
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.BottomSheetUtil
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.NetworkUtil
|
||||
import org.thoughtcrime.securesms.util.SupportEmailUtil
|
||||
|
||||
class DebugLogsPromptDialogFragment : FixedRoundedCornerBottomSheetDialogFragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun show(context: Context, fragmentManager: FragmentManager) {
|
||||
if (NetworkUtil.isConnected(context) && fragmentManager.findFragmentByTag(BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) == null) {
|
||||
DebugLogsPromptDialogFragment().apply {
|
||||
arguments = bundleOf()
|
||||
}.show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
SignalStore.uiHints().lastNotificationLogsPrompt = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val peekHeightPercentage: Float = 0.66f
|
||||
override val themeResId: Int = R.style.Widget_Signal_FixedRoundedCorners_Messages
|
||||
|
||||
private val binding by ViewBinderDelegate(PromptLogsBottomSheetBinding::bind)
|
||||
|
||||
private lateinit var viewModel: PromptLogsViewModel
|
||||
|
||||
private val disposables: LifecycleDisposable = LifecycleDisposable()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
return inflater.inflate(R.layout.prompt_logs_bottom_sheet, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
disposables.bindTo(viewLifecycleOwner)
|
||||
|
||||
viewModel = ViewModelProvider(this).get(PromptLogsViewModel::class.java)
|
||||
binding.submit.setOnClickListener {
|
||||
val progressDialog = SignalProgressDialog.show(requireContext())
|
||||
disposables += viewModel.submitLogs().subscribe({ result ->
|
||||
submitLogs(result)
|
||||
progressDialog.dismiss()
|
||||
dismiss()
|
||||
}, { _ ->
|
||||
Toast.makeText(requireContext(), getString(R.string.HelpFragment__could_not_upload_logs), Toast.LENGTH_LONG).show()
|
||||
progressDialog.dismiss()
|
||||
dismiss()
|
||||
})
|
||||
}
|
||||
binding.decline.setOnClickListener {
|
||||
SignalStore.uiHints().markDeclinedShareNotificationLogs()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun submitLogs(debugLog: String) {
|
||||
CommunicationActions.openEmail(
|
||||
requireContext(),
|
||||
SupportEmailUtil.getSupportEmailAddress(requireContext()),
|
||||
getString(R.string.DebugLogsPromptDialogFragment__signal_android_support_request),
|
||||
getEmailBody(debugLog)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getEmailBody(debugLog: String?): String {
|
||||
val suffix = StringBuilder()
|
||||
if (debugLog != null) {
|
||||
suffix.append("\n")
|
||||
suffix.append(getString(R.string.HelpFragment__debug_log))
|
||||
suffix.append(" ")
|
||||
suffix.append(debugLog)
|
||||
}
|
||||
val category = ResourceUtil.getEnglishResources(requireContext()).getString(R.string.DebugLogsPromptDialogFragment__slow_notifications_category)
|
||||
return SupportEmailUtil.generateSupportEmailBody(
|
||||
requireContext(),
|
||||
R.string.DebugLogsPromptDialogFragment__signal_android_support_request,
|
||||
" - $category",
|
||||
"\n\n",
|
||||
suffix.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import io.reactivex.rxjava3.subjects.SingleSubject
|
||||
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogRepository
|
||||
|
||||
class PromptLogsViewModel : ViewModel() {
|
||||
|
||||
private val submitDebugLogRepository = SubmitDebugLogRepository()
|
||||
|
||||
fun submitLogs(): Single<String> {
|
||||
val singleSubject = SingleSubject.create<String?>()
|
||||
submitDebugLogRepository.buildAndSubmitLog { result ->
|
||||
if (result.isPresent) {
|
||||
singleSubject.onSuccess(result.get())
|
||||
} else {
|
||||
singleSubject.onError(Throwable())
|
||||
}
|
||||
}
|
||||
|
||||
return singleSubject.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ public class UiHints extends SignalStoreValues {
|
||||
private static final String HAS_SEEN_TEXT_FORMATTING_ALERT = "uihints.text_formatting.has_seen_alert";
|
||||
private static final String HAS_NOT_SEEN_EDIT_MESSAGE_BETA_ALERT = "uihints.edit_message.has_not_seen_beta_alert";
|
||||
private static final String HAS_SEEN_SAFETY_NUMBER_NUX = "uihints.has_seen_safety_number_nux";
|
||||
private static final String DECLINED_NOTIFICATION_LOGS_PROMPT = "uihints.declined_notification_logs";
|
||||
private static final String LAST_NOTIFICATION_LOGS_PROMPT_TIME = "uihints.last_notification_logs_prompt";
|
||||
|
||||
UiHints(@NonNull KeyValueStore store) {
|
||||
super(store);
|
||||
@@ -118,4 +120,20 @@ public class UiHints extends SignalStoreValues {
|
||||
public void markHasSeenSafetyNumberUpdateNux() {
|
||||
putBoolean(HAS_SEEN_SAFETY_NUMBER_NUX, true);
|
||||
}
|
||||
|
||||
public long getLastNotificationLogsPrompt() {
|
||||
return getLong(LAST_NOTIFICATION_LOGS_PROMPT_TIME, 0);
|
||||
}
|
||||
|
||||
public void setLastNotificationLogsPrompt(long timeMs) {
|
||||
putLong(LAST_NOTIFICATION_LOGS_PROMPT_TIME, timeMs);
|
||||
}
|
||||
|
||||
public void markDeclinedShareNotificationLogs() {
|
||||
putBoolean(DECLINED_NOTIFICATION_LOGS_PROMPT, true);
|
||||
}
|
||||
|
||||
public boolean hasDeclinedToShareNotificationLogs() {
|
||||
return getBoolean(DECLINED_NOTIFICATION_LOGS_PROMPT, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,18 @@
|
||||
|
||||
package org.thoughtcrime.securesms.notifications
|
||||
|
||||
import android.text.TextUtils
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.database.LocalMetricsDatabase
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
import org.thoughtcrime.securesms.util.LocaleFeatureFlags
|
||||
import org.thoughtcrime.securesms.util.SignalLocalMetrics
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
|
||||
/**
|
||||
* Heuristic for estimating if a user has been experiencing issues with delayed notifications.
|
||||
@@ -22,6 +30,44 @@ object SlowNotificationHeuristics {
|
||||
|
||||
private val TAG = Log.tag(SlowNotificationHeuristics::class.java)
|
||||
|
||||
fun getConfiguration(): Configuration {
|
||||
val json = FeatureFlags.delayedNotificationsPromptConfig()
|
||||
return if (TextUtils.isEmpty(json)) {
|
||||
getDefaultConfiguration()
|
||||
} else {
|
||||
try {
|
||||
JsonUtils.fromJson(json, Configuration::class.java)
|
||||
} catch (exception: Exception) {
|
||||
getDefaultConfiguration()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDefaultConfiguration(): Configuration {
|
||||
return Configuration(
|
||||
minimumEventAgeMs = 3.days.inWholeMilliseconds,
|
||||
minimumServiceEventCount = 10,
|
||||
serviceStartFailurePercentage = 0.5f,
|
||||
messageLatencyPercentage = 75,
|
||||
messageLatencyThreshold = 6.hours.inWholeMilliseconds,
|
||||
minimumMessageLatencyEvents = 50,
|
||||
weeklyFailedQueueDrains = 5
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shouldPromptUserForLogs(): Boolean {
|
||||
if (!LocaleFeatureFlags.isDelayedNotificationPromptEnabled() || SignalStore.uiHints().hasDeclinedToShareNotificationLogs()) {
|
||||
return false
|
||||
}
|
||||
if (System.currentTimeMillis() - SignalStore.uiHints().lastNotificationLogsPrompt < TimeUnit.DAYS.toMillis(7)) {
|
||||
return false
|
||||
}
|
||||
val configuration = getConfiguration()
|
||||
|
||||
return isHavingDelayedNotifications(configuration)
|
||||
}
|
||||
|
||||
fun isHavingDelayedNotifications(configuration: Configuration): Boolean {
|
||||
val db = LocalMetricsDatabase.getInstance(ApplicationDependencies.getApplication())
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.groups.SelectionLimits;
|
||||
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.messageprocessingalarm.MessageProcessReceiver;
|
||||
import org.thoughtcrime.securesms.notifications.Configuration;
|
||||
import org.whispersystems.signalservice.api.RemoteConfigResult;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -109,6 +110,8 @@ public final class FeatureFlags {
|
||||
private static final String CDS_DISABLE_COMPAT_MODE = "cds.disableCompatibilityMode";
|
||||
private static final String FCM_MAY_HAVE_MESSAGES_KILL_SWITCH = "android.fcmNotificationFallbackKillSwitch";
|
||||
private static final String SAFETY_NUMBER_ACI = "global.safetyNumberAci";
|
||||
public static final String PROMPT_FOR_NOTIFICATION_LOGS = "android.logs.promptNotifications";
|
||||
private static final String PROMPT_FOR_NOTIFICATION_CONFIG = "android.logs.promptNotificationsConfig";
|
||||
|
||||
/**
|
||||
* We will only store remote values for flags in this set. If you want a flag to be controllable
|
||||
@@ -169,7 +172,9 @@ public final class FeatureFlags {
|
||||
SVR2_KILLSWITCH,
|
||||
CDS_DISABLE_COMPAT_MODE,
|
||||
SAFETY_NUMBER_ACI,
|
||||
FCM_MAY_HAVE_MESSAGES_KILL_SWITCH
|
||||
FCM_MAY_HAVE_MESSAGES_KILL_SWITCH,
|
||||
PROMPT_FOR_NOTIFICATION_LOGS,
|
||||
PROMPT_FOR_NOTIFICATION_CONFIG
|
||||
);
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -236,7 +241,9 @@ public final class FeatureFlags {
|
||||
SVR2_KILLSWITCH,
|
||||
CDS_DISABLE_COMPAT_MODE,
|
||||
SAFETY_NUMBER_ACI,
|
||||
FCM_MAY_HAVE_MESSAGES_KILL_SWITCH
|
||||
FCM_MAY_HAVE_MESSAGES_KILL_SWITCH,
|
||||
PROMPT_FOR_NOTIFICATION_LOGS,
|
||||
PROMPT_FOR_NOTIFICATION_CONFIG
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -618,6 +625,13 @@ public final class FeatureFlags {
|
||||
}
|
||||
}
|
||||
|
||||
public static String promptForDelayedNotificationLogs() {
|
||||
return getString(PROMPT_FOR_NOTIFICATION_LOGS, "*");
|
||||
}
|
||||
|
||||
public static String delayedNotificationsPromptConfig() {
|
||||
return getString(PROMPT_FOR_NOTIFICATION_CONFIG, "");
|
||||
}
|
||||
/** Only for rendering debug info. */
|
||||
public static synchronized @NonNull Map<String, Object> getMemoryValues() {
|
||||
return new TreeMap<>(REMOTE_VALUES);
|
||||
|
||||
@@ -65,6 +65,9 @@ public final class LocaleFeatureFlags {
|
||||
return isEnabled(FeatureFlags.PAYPAL_DISABLED_REGIONS, FeatureFlags.paypalDisabledRegions());
|
||||
}
|
||||
|
||||
public static boolean isDelayedNotificationPromptEnabled() {
|
||||
return isEnabled(FeatureFlags.PROMPT_FOR_NOTIFICATION_LOGS, FeatureFlags.promptForDelayedNotificationLogs());
|
||||
}
|
||||
/**
|
||||
* Parses a comma-separated list of country codes colon-separated from how many buckets out of 1 million
|
||||
* should be enabled to see this megaphone in that country code. At the end of the list, an optional
|
||||
|
||||
@@ -33,6 +33,11 @@ public final class NetworkUtil {
|
||||
return info != null && info.isConnected() && info.isRoaming() && info.getType() == ConnectivityManager.TYPE_MOBILE;
|
||||
}
|
||||
|
||||
public static boolean isConnected(@NonNull Context context) {
|
||||
final NetworkInfo info = getNetworkInfo(context);
|
||||
return info != null && info.isConnected();
|
||||
}
|
||||
|
||||
public static @NonNull CallManager.DataMode getCallingDataMode(@NonNull Context context) {
|
||||
return getCallingDataMode(context, PeerConnection.AdapterType.UNKNOWN);
|
||||
}
|
||||
|
||||
44
app/src/main/res/drawable/ic_debug_log.xml
Normal file
44
app/src/main/res/drawable/ic_debug_log.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:viewportWidth="72"
|
||||
android:viewportHeight="72">
|
||||
<path
|
||||
android:pathData="M13.5,19.8C13.5,16.02 13.5,14.13 14.236,12.686C14.883,11.415 15.915,10.383 17.186,9.736C18.629,9 20.52,9 24.3,9H47.7C51.48,9 53.37,9 54.814,9.736C56.084,10.383 57.117,11.415 57.764,12.686C58.5,14.13 58.5,16.02 58.5,19.8V56.7C58.5,60.48 58.5,62.37 57.764,63.814C57.117,65.085 56.084,66.117 54.814,66.764C53.37,67.5 51.48,67.5 47.7,67.5H24.3C20.52,67.5 18.629,67.5 17.186,66.764C15.915,66.117 14.883,65.085 14.236,63.814C13.5,62.37 13.5,60.48 13.5,56.7V19.8Z"
|
||||
android:fillColor="#DDE7FF"/>
|
||||
<path
|
||||
android:pathData="M17.901,9.442L53.942,67.107C52.592,67.5 50.769,67.5 47.7,67.5H24.3C20.52,67.5 18.629,67.5 17.186,66.764C15.915,66.117 14.883,65.085 14.236,63.814C13.5,62.37 13.5,60.48 13.5,56.7V19.8C13.5,16.02 13.5,14.13 14.236,12.686C14.883,11.415 15.915,10.383 17.186,9.736C17.411,9.621 17.648,9.524 17.901,9.442Z"
|
||||
android:fillColor="#C7D1E5"/>
|
||||
<path
|
||||
android:pathData="M19.5,43.5C19.5,42.672 20.172,42 21,42L51,42C51.828,42 52.5,42.672 52.5,43.5C52.5,44.328 51.828,45 51,45L21,45C20.172,45 19.5,44.328 19.5,43.5Z"
|
||||
android:fillColor="#8997B5"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M19.5,50.25C19.5,49.422 20.172,48.75 21,48.75L51,48.75C51.828,48.75 52.5,49.422 52.5,50.25C52.5,51.078 51.828,51.75 51,51.75L21,51.75C20.172,51.75 19.5,51.078 19.5,50.25Z"
|
||||
android:fillColor="#8997B5"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M19.5,57C19.5,56.172 20.172,55.5 21,55.5L51,55.5C51.828,55.5 52.5,56.172 52.5,57C52.5,57.828 51.828,58.5 51,58.5L21,58.5C20.172,58.5 19.5,57.828 19.5,57Z"
|
||||
android:fillColor="#8997B5"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M24.235,7.5H47.765C49.6,7.5 51.069,7.5 52.256,7.597C53.474,7.696 54.527,7.906 55.495,8.399C57.048,9.19 58.31,10.452 59.101,12.005C59.594,12.973 59.804,14.026 59.903,15.245C60,16.431 60,17.9 60,19.735V56.765C60,58.6 60,60.069 59.903,61.256C59.804,62.474 59.594,63.527 59.101,64.495C58.31,66.048 57.048,67.31 55.495,68.101C54.527,68.594 53.474,68.803 52.256,68.903C51.069,69 49.6,69 47.765,69H24.235C22.4,69 20.931,69 19.744,68.903C18.526,68.803 17.473,68.594 16.505,68.101C14.952,67.31 13.69,66.048 12.899,64.495C12.406,63.527 12.196,62.474 12.097,61.256C12,60.069 12,58.6 12,56.765V19.735C12,17.9 12,16.431 12.097,15.245C12.196,14.026 12.406,12.973 12.899,12.005C13.69,10.452 14.952,9.19 16.505,8.399C17.473,7.906 18.526,7.696 19.744,7.597C20.931,7.5 22.4,7.5 24.235,7.5ZM19.989,10.587C18.956,10.671 18.342,10.83 17.867,11.072C16.879,11.576 16.076,12.379 15.572,13.367C15.33,13.842 15.171,14.456 15.087,15.489C15.001,16.539 15,17.885 15,19.8V56.7C15,58.615 15.001,59.961 15.087,61.011C15.171,62.044 15.33,62.658 15.572,63.133C16.076,64.121 16.879,64.924 17.867,65.428C18.342,65.67 18.956,65.829 19.989,65.913C21.039,65.999 22.385,66 24.3,66H47.7C49.615,66 50.961,65.999 52.011,65.913C53.044,65.829 53.658,65.67 54.133,65.428C55.121,64.924 55.924,64.121 56.428,63.133C56.67,62.658 56.829,62.044 56.913,61.011C56.999,59.961 57,58.615 57,56.7V19.8C57,17.885 56.999,16.539 56.913,15.489C56.829,14.456 56.67,13.842 56.428,13.367C55.924,12.379 55.121,11.576 54.133,11.072C53.658,10.83 53.044,10.671 52.011,10.587C50.961,10.501 49.615,10.5 47.7,10.5H24.3C22.385,10.5 21.039,10.501 19.989,10.587Z"
|
||||
android:fillColor="#6C7B9D"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M30.75,2.25C30.75,1.007 31.757,0 33,0H39C40.243,0 41.25,1.007 41.25,2.25V5.25H45.75C46.993,5.25 48,6.257 48,7.5V11.25C48,12.493 46.993,13.5 45.75,13.5H26.25C25.007,13.5 24,12.493 24,11.25V7.5C24,6.257 25.007,5.25 26.25,5.25H30.75V2.25ZM36,5.5C36.966,5.5 37.75,4.716 37.75,3.75C37.75,2.783 36.966,2 36,2C35.034,2 34.25,2.783 34.25,3.75C34.25,4.716 35.034,5.5 36,5.5Z"
|
||||
android:fillColor="#4C5876"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M24,10.5H48V11.25C48,12.493 46.993,13.5 45.75,13.5H26.25C25.007,13.5 24,12.493 24,11.25V10.5Z"
|
||||
android:fillColor="#8997B5"/>
|
||||
<path
|
||||
android:pathData="M34.051,19.125C34.917,17.625 37.083,17.625 37.949,19.125L45.743,32.625C46.609,34.125 45.526,36 43.794,36H28.206C26.474,36 25.391,34.125 26.257,32.625L34.051,19.125Z"
|
||||
android:fillColor="#FA902E"/>
|
||||
<path
|
||||
android:pathData="M36,32.375m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"
|
||||
android:fillColor="#FFE3A5"/>
|
||||
<path
|
||||
android:pathData="M36,22.25C36.842,22.25 37.505,22.97 37.435,23.81L37.018,28.813C36.974,29.343 36.531,29.75 36,29.75C35.469,29.75 35.026,29.343 34.982,28.813L34.565,23.81C34.495,22.97 35.158,22.25 36,22.25Z"
|
||||
android:fillColor="#FFE3A5"/>
|
||||
</vector>
|
||||
87
app/src/main/res/layout/prompt_logs_bottom_sheet.xml
Normal file
87
app/src/main/res/layout/prompt_logs_bottom_sheet.xml
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2023 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="2dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/signal_icon_tint_tab_unselected"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_debug_log"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
|
||||
<TextView
|
||||
style="@style/Signal.Text.TitleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/PromptLogsSlowNotificationsDialog__title"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
style="@style/Signal.Text.BodyMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginHorizontal="24dp"
|
||||
android:text="@string/PromptLogsSlowNotificationsDialog__message"
|
||||
/>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:minWidth="320dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginHorizontal="34dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/decline"
|
||||
style="@style/Signal.Widget.Button.Medium.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:minWidth="160dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:text="@string/DebugLogsPromptDialogFragment__no_thanks"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/submit"
|
||||
style="@style/Signal.Widget.Button.Medium.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:minWidth="160dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:text="@string/DebugLogsPromptDialogFragment__submit"/>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
@@ -905,6 +905,11 @@
|
||||
<item quantity="other">%1$d members</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Title for dialog asking user to submit logs for debugging slow notification issues -->
|
||||
<string name="PromptLogsSlowNotificationsDialog__title">We noticed notifications are delayed. Submit debug log?</string>
|
||||
<!-- Message for dialog asking user to submit logs for debugging slow notification issues -->
|
||||
<string name="PromptLogsSlowNotificationsDialog__message">Debug logs helps us diagnose and fix the issue, and do not contain identifying information.</string>
|
||||
|
||||
<!-- PendingMembersActivity -->
|
||||
<string name="PendingMembersActivity_pending_group_invites">Pending group invites</string>
|
||||
<string name="PendingMembersActivity_requests">Requests</string>
|
||||
@@ -2866,6 +2871,14 @@
|
||||
<item>Donations & Badges</item>
|
||||
<item>SMS Export</item>
|
||||
</string-array>
|
||||
<!-- Subject of email when submitting debug logs to help debug slow notifications -->
|
||||
<string name="DebugLogsPromptDialogFragment__signal_android_support_request">Signal Android Debug Log Submission</string>
|
||||
<!-- Category to organize the support email sent -->
|
||||
<string name="DebugLogsPromptDialogFragment__slow_notifications_category">Slow notifications</string>
|
||||
<!-- Action to submit logs and take user to send an e-mail -->
|
||||
<string name="DebugLogsPromptDialogFragment__submit">Submit</string>
|
||||
<!-- Action to decline to submit logs -->
|
||||
<string name="DebugLogsPromptDialogFragment__no_thanks">No thanks</string>
|
||||
|
||||
<!-- ReactWithAnyEmojiBottomSheetDialogFragment -->
|
||||
<string name="ReactWithAnyEmojiBottomSheetDialogFragment__this_message">This Message</string>
|
||||
|
||||
Reference in New Issue
Block a user