From 6a8e82ef91af22be1db5441dce80f3eb267e0ca3 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Thu, 2 Feb 2023 09:51:45 -0500 Subject: [PATCH] Prevent scheduling of sends when alarm permission is denied. --- .../ConversationParentFragment.java | 14 ++++++-- ...ReenableScheduledMessagesDialogFragment.kt | 28 +++++++++++----- .../ScheduleMessageDialogCallback.java | 13 ++++++++ .../ScheduleMessageFtuxBottomSheetDialog.kt | 33 +++++++++---------- 4 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageDialogCallback.java diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index 8dddd9a0b3..251701d34f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -366,7 +366,8 @@ public class ConversationParentFragment extends Fragment Material3OnScrollHelperBinder, MessageDetailsFragment.Callback, ScheduleMessageTimePickerBottomSheet.ScheduleCallback, - ConversationBottomSheetCallback + ConversationBottomSheetCallback, + ScheduleMessageDialogCallback { private static final int SHORTCUT_ICON_SIZE = Build.VERSION.SDK_INT >= 26 ? ViewUtil.dpToPx(72) : ViewUtil.dpToPx(48 + 16 * 2); @@ -2948,9 +2949,10 @@ public class ConversationParentFragment extends Fragment } private void sendMessage(@Nullable String metricId, long scheduledDate) { - if (scheduledDate != -1) { - ReenableScheduledMessagesDialogFragment.showIfNeeded(requireContext(), getChildFragmentManager()); + if (scheduledDate != -1 && ReenableScheduledMessagesDialogFragment.showIfNeeded(requireContext(), getChildFragmentManager(), metricId, scheduledDate)) { + return; } + if (inputPanel.isRecordingInLockedMode()) { inputPanel.releaseRecordingLock(); return; @@ -3671,6 +3673,7 @@ public class ConversationParentFragment extends Fragment }); } + @Override public void onScheduleSend(long scheduledTime) { sendMessage(null, scheduledTime); } @@ -3685,6 +3688,11 @@ public class ConversationParentFragment extends Fragment fragment.jumpToMessage(messageRecord); } + @Override + public void onSchedulePermissionsGranted(@Nullable String metricId, long scheduledDate) { + sendMessage(metricId, scheduledDate); + } + // Listeners private class RecordingSession implements SingleObserver, Disposable { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ReenableScheduledMessagesDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ReenableScheduledMessagesDialogFragment.kt index 84ee070644..84ead84578 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ReenableScheduledMessagesDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ReenableScheduledMessagesDialogFragment.kt @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.conversation import android.annotation.SuppressLint -import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri @@ -13,13 +12,14 @@ import android.view.View import android.view.ViewGroup import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.os.bundleOf import androidx.fragment.app.FragmentManager import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.FixedRoundedCornerBottomSheetDialogFragment -import org.thoughtcrime.securesms.conversation.ScheduleMessageFtuxBottomSheetDialog.Companion.show import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.util.BottomSheetUtil import org.thoughtcrime.securesms.util.ServiceUtil +import org.thoughtcrime.securesms.util.fragments.findListener /** * Bottom sheet dialog to prompt user to enable schedule alarms permission for scheduling messages @@ -35,7 +35,11 @@ class ReenableScheduledMessagesDialogFragment : FixedRoundedCornerBottomSheetDia @SuppressLint("InlinedApi") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val launcher: ActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { + if (Build.VERSION.SDK_INT < 31 || ServiceUtil.getAlarmManager(context).canScheduleExactAlarms()) { + findListener()?.onSchedulePermissionsGranted( + requireArguments().getString(ScheduleMessageDialogCallback.ARGUMENT_METRIC_ID), + requireArguments().getLong(ScheduleMessageDialogCallback.ARGUMENT_SCHEDULED_DATE) + ) dismissAllowingStateLoss() } } @@ -47,12 +51,9 @@ class ReenableScheduledMessagesDialogFragment : FixedRoundedCornerBottomSheetDia companion object { @JvmStatic - fun showIfNeeded(context: Context, fragmentManager: FragmentManager) { - var hasPermission = true - if (Build.VERSION.SDK_INT >= 31) { - val alarmManager = ServiceUtil.getAlarmManager(context) - hasPermission = alarmManager.canScheduleExactAlarms() - } + fun showIfNeeded(context: Context, fragmentManager: FragmentManager, metricId: String?, scheduledDate: Long): Boolean { + val hasPermission = Build.VERSION.SDK_INT < 31 || ServiceUtil.getAlarmManager(context).canScheduleExactAlarms() + val fragment = if (!SignalStore.uiHints().hasSeenScheduledMessagesInfoSheet()) { ScheduleMessageFtuxBottomSheetDialog() } else if (!hasPermission) { @@ -60,7 +61,16 @@ class ReenableScheduledMessagesDialogFragment : FixedRoundedCornerBottomSheetDia } else { null } + + fragment?.apply { + arguments = bundleOf( + ScheduleMessageDialogCallback.ARGUMENT_METRIC_ID to metricId, + ScheduleMessageDialogCallback.ARGUMENT_SCHEDULED_DATE to scheduledDate + ) + } fragment?.show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) + + return fragment != null } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageDialogCallback.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageDialogCallback.java new file mode 100644 index 0000000000..2bfccf5dc5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageDialogCallback.java @@ -0,0 +1,13 @@ +package org.thoughtcrime.securesms.conversation; + +import javax.annotation.Nullable; + +/** + * Interface for responding to scheduled message dialogs blocking the send flow for permissions check. + */ +public interface ScheduleMessageDialogCallback { + String ARGUMENT_METRIC_ID = "ARGUMENT_METRIC_ID"; + String ARGUMENT_SCHEDULED_DATE = "ARGUMENT_SCHEDULED_DATE"; + + void onSchedulePermissionsGranted(@Nullable String metricId, long scheduledDate); +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageFtuxBottomSheetDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageFtuxBottomSheetDialog.kt index 22839eedb3..135b26bb45 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageFtuxBottomSheetDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ScheduleMessageFtuxBottomSheetDialog.kt @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms.conversation -import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Build @@ -11,14 +10,13 @@ import android.view.View import android.view.ViewGroup import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts -import androidx.fragment.app.FragmentManager import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.FixedRoundedCornerBottomSheetDialogFragment import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.databinding.ScheduleMessageFtuxBottomSheetBinding import org.thoughtcrime.securesms.keyvalue.SignalStore -import org.thoughtcrime.securesms.util.BottomSheetUtil import org.thoughtcrime.securesms.util.ServiceUtil +import org.thoughtcrime.securesms.util.fragments.findListener class ScheduleMessageFtuxBottomSheetDialog : FixedRoundedCornerBottomSheetDialogFragment() { override val peekHeightPercentage: Float = 0.66f @@ -34,29 +32,30 @@ class ScheduleMessageFtuxBottomSheetDialog : FixedRoundedCornerBottomSheetDialog if (Build.VERSION.SDK_INT >= 31 && !ServiceUtil.getAlarmManager(context).canScheduleExactAlarms()) { binding.reenableSettings.visibility = View.VISIBLE binding.okay.visibility = View.GONE + val launcher: ActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - dismissAllowingStateLoss() + if (Build.VERSION.SDK_INT < 31 || ServiceUtil.getAlarmManager(context).canScheduleExactAlarms()) { + proceedWithScheduledSend() } } + binding.enableScheduledMessagesGoToSettings.setOnClickListener { SignalStore.uiHints().markHasSeenScheduledMessagesInfoSheet() launcher.launch(Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM, Uri.parse("package:" + requireContext().packageName))) - dismiss() + } + } else { + binding.okay.setOnClickListener { + proceedWithScheduledSend() } } - binding.okay.setOnClickListener { - SignalStore.uiHints().markHasSeenScheduledMessagesInfoSheet() - dismiss() - } } - companion object { - @JvmStatic - fun show(fragmentManager: FragmentManager) { - val fragment = ScheduleMessageFtuxBottomSheetDialog() - - fragment.show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) - } + private fun proceedWithScheduledSend() { + SignalStore.uiHints().markHasSeenScheduledMessagesInfoSheet() + findListener()?.onSchedulePermissionsGranted( + requireArguments().getString(ScheduleMessageDialogCallback.ARGUMENT_METRIC_ID), + requireArguments().getLong(ScheduleMessageDialogCallback.ARGUMENT_SCHEDULED_DATE) + ) + dismissAllowingStateLoss() } }