mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-26 03:40:56 +01:00
Improve Call Notification UX when things don't go as planned.
This commit is contained in:
committed by
Alex Hart
parent
b053fbc4a7
commit
d8dead82b6
@@ -88,6 +88,7 @@ import org.thoughtcrime.securesms.contactshare.SharedContactDetailsActivity;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickListener;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter.StickyHeaderViewHolder;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
|
||||
import org.thoughtcrime.securesms.conversation.ui.error.EnableCallNotificationSettingsDialog;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
@@ -1558,6 +1559,23 @@ public class ConversationFragment extends LoggingFragment {
|
||||
public void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId) {
|
||||
GroupLinkInviteFriendsBottomSheetDialogFragment.show(requireActivity().getSupportFragmentManager(), groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnableCallNotificationsClicked() {
|
||||
EnableCallNotificationSettingsDialog.fixAutomatically(requireContext());
|
||||
if (EnableCallNotificationSettingsDialog.shouldShow(requireContext())) {
|
||||
EnableCallNotificationSettingsDialog.show(getChildFragmentManager());
|
||||
} else {
|
||||
refreshList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshList() {
|
||||
ConversationAdapter listAdapter = getListAdapter();
|
||||
if (listAdapter != null) {
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.BindableConversationItem;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.VerifyIdentityActivity;
|
||||
import org.thoughtcrime.securesms.conversation.ui.error.EnableCallNotificationSettingsDialog;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
||||
import org.thoughtcrime.securesms.database.model.LiveUpdateMessage;
|
||||
@@ -302,6 +303,14 @@ public final class ConversationUpdateItem extends FrameLayout
|
||||
eventListener.onInviteFriendsToGroupClicked(conversationRecipient.requireGroupId().requireV2());
|
||||
}
|
||||
});
|
||||
} else if ((conversationMessage.getMessageRecord().isMissedAudioCall() || conversationMessage.getMessageRecord().isMissedVideoCall()) && EnableCallNotificationSettingsDialog.shouldShow(getContext())) {
|
||||
actionButton.setVisibility(VISIBLE);
|
||||
actionButton.setText(R.string.ConversationUpdateItem_enable_call_notifications);
|
||||
actionButton.setOnClickListener(v -> {
|
||||
if (eventListener != null) {
|
||||
eventListener.onEnableCallNotificationsClicked();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
actionButton.setVisibility(GONE);
|
||||
actionButton.setOnClickListener(null);
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
package org.thoughtcrime.securesms.conversation.ui.error;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationFragment;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.util.DeviceProperties;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
/**
|
||||
* Provide basic steps to fix potential call notification issues based on what we can detect on the system
|
||||
* and app settings.
|
||||
*/
|
||||
@TargetApi(26)
|
||||
public final class EnableCallNotificationSettingsDialog extends DialogFragment {
|
||||
|
||||
private static final String TAG = Log.tag(EnableCallNotificationSettingsDialog.class);
|
||||
private static final String FRAGMENT_TAG = "MissedCallCheckSettingsDialog";
|
||||
|
||||
private static final int NOTIFICATIONS_DISABLED = 1 << 1;
|
||||
private static final int CALL_NOTIFICATIONS_DISABLED = 1 << 2;
|
||||
private static final int CALL_CHANNEL_INVALID = 1 << 4;
|
||||
private static final int BACKGROUND_RESTRICTED = 1 << 8;
|
||||
|
||||
private View view;
|
||||
|
||||
public static boolean shouldShow(@NonNull Context context) {
|
||||
return getCallNotificationSettingsBitmask(context) != 0;
|
||||
}
|
||||
|
||||
public static void fixAutomatically(@NonNull Context context) {
|
||||
if (areCallNotificationsDisabled(context)) {
|
||||
TextSecurePreferences.setCallNotificationsEnabled(context, true);
|
||||
Toast.makeText(context, R.string.EnableCallNotificationSettingsDialog__call_notifications_enabled, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
public static void show(@NonNull FragmentManager fragmentManager) {
|
||||
if (fragmentManager.findFragmentByTag(FRAGMENT_TAG) != null) {
|
||||
Log.i(TAG, "Dialog already being shown");
|
||||
return;
|
||||
}
|
||||
|
||||
new EnableCallNotificationSettingsDialog().show(fragmentManager, FRAGMENT_TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(requireContext(), R.style.Signal_ThemeOverlay_Dialog_Rounded);
|
||||
|
||||
Runnable action = null;
|
||||
switch (getCallNotificationSettingsBitmask(requireContext())) {
|
||||
case NOTIFICATIONS_DISABLED:
|
||||
dialogBuilder.setTitle(R.string.EnableCallNotificationSettingsDialog__enable_call_notifications)
|
||||
.setMessage(R.string.EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_settings_and_turn_on_show_notifications)
|
||||
.setPositiveButton(R.string.EnableCallNotificationSettingsDialog__settings, null);
|
||||
action = this::showNotificationSettings;
|
||||
break;
|
||||
case CALL_CHANNEL_INVALID:
|
||||
dialogBuilder.setTitle(R.string.EnableCallNotificationSettingsDialog__enable_call_notifications)
|
||||
.setMessage(R.string.EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_settings_and_turn_on_notifications)
|
||||
.setPositiveButton(R.string.EnableCallNotificationSettingsDialog__settings, null);
|
||||
action = this::showNotificationChannelSettings;
|
||||
break;
|
||||
case BACKGROUND_RESTRICTED:
|
||||
dialogBuilder.setTitle(R.string.EnableCallNotificationSettingsDialog__enable_background_activity)
|
||||
.setMessage(R.string.EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_settings_and_enable_background_activity_in_battery_settings)
|
||||
.setPositiveButton(R.string.EnableCallNotificationSettingsDialog__settings, null);
|
||||
action = this::showAppSettings;
|
||||
break;
|
||||
default:
|
||||
dialogBuilder.setTitle(R.string.EnableCallNotificationSettingsDialog__enable_call_notifications)
|
||||
.setView(createView())
|
||||
.setPositiveButton(android.R.string.ok, null);
|
||||
break;
|
||||
}
|
||||
|
||||
dialogBuilder.setNegativeButton(android.R.string.cancel, null);
|
||||
|
||||
AlertDialog dialog = dialogBuilder.create();
|
||||
|
||||
if (action != null) {
|
||||
final Runnable localAction = action;
|
||||
dialog.setOnShowListener(d -> dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> localAction.run()));
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (getCallNotificationSettingsBitmask(requireContext()) == 0) {
|
||||
dismissAllowingStateLoss();
|
||||
} else if (view != null) {
|
||||
bind(view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
if (getParentFragment() instanceof ConversationFragment) {
|
||||
((ConversationFragment) getParentFragment()).refreshList();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
private @NonNull View createView() {
|
||||
view = LayoutInflater.from(getContext()).inflate(R.layout.enable_call_notification_settings_dialog_fragment, null, false);
|
||||
bind(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
private void bind(@NonNull View view) {
|
||||
TextView allConfigured = view.findViewById(R.id.enable_call_notification_settings_dialog_system_all_configured);
|
||||
AppCompatImageView systemSettingIndicator = view.findViewById(R.id.enable_call_notification_settings_dialog_system_setting_indicator);
|
||||
TextView systemSettingText = view.findViewById(R.id.enable_call_notification_settings_dialog_system_setting_text);
|
||||
AppCompatImageView channelSettingIndicator = view.findViewById(R.id.enable_call_notification_settings_dialog_channel_setting_indicator);
|
||||
TextView channelSettingText = view.findViewById(R.id.enable_call_notification_settings_dialog_channel_setting_text);
|
||||
AppCompatImageView backgroundRestrictedIndicator = view.findViewById(R.id.enable_call_notification_settings_dialog_background_restricted_indicator);
|
||||
TextView backgroundRestrictedText = view.findViewById(R.id.enable_call_notification_settings_dialog_background_restricted_text);
|
||||
|
||||
if (areNotificationsDisabled(requireContext())) {
|
||||
systemSettingIndicator.setVisibility(View.VISIBLE);
|
||||
systemSettingText.setVisibility(View.VISIBLE);
|
||||
systemSettingText.setOnClickListener(v -> showNotificationSettings());
|
||||
} else {
|
||||
systemSettingIndicator.setVisibility(View.GONE);
|
||||
systemSettingText.setVisibility(View.GONE);
|
||||
systemSettingText.setOnClickListener(null);
|
||||
}
|
||||
|
||||
if (isCallChannelInvalid(requireContext())) {
|
||||
channelSettingIndicator.setVisibility(View.VISIBLE);
|
||||
channelSettingText.setVisibility(View.VISIBLE);
|
||||
channelSettingText.setOnClickListener(v -> showNotificationChannelSettings());
|
||||
} else {
|
||||
channelSettingIndicator.setVisibility(View.GONE);
|
||||
channelSettingText.setVisibility(View.GONE);
|
||||
channelSettingText.setOnClickListener(null);
|
||||
}
|
||||
|
||||
if (isBackgroundRestricted(requireContext())) {
|
||||
backgroundRestrictedIndicator.setVisibility(View.VISIBLE);
|
||||
backgroundRestrictedText.setVisibility(View.VISIBLE);
|
||||
backgroundRestrictedText.setOnClickListener(v -> showAppSettings());
|
||||
} else {
|
||||
backgroundRestrictedIndicator.setVisibility(View.GONE);
|
||||
backgroundRestrictedText.setVisibility(View.GONE);
|
||||
backgroundRestrictedText.setOnClickListener(null);
|
||||
}
|
||||
|
||||
allConfigured.setVisibility(shouldShow(requireContext()) ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
private void showNotificationSettings() {
|
||||
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().getPackageName());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void showNotificationChannelSettings() {
|
||||
NotificationChannels.openChannelSettings(requireContext(), NotificationChannels.CALLS);
|
||||
}
|
||||
|
||||
private void showAppSettings() {
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
Uri.fromParts("package", requireContext().getPackageName(), null));
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private static boolean areNotificationsDisabled(@NonNull Context context) {
|
||||
return !NotificationChannels.areNotificationsEnabled(context);
|
||||
}
|
||||
|
||||
private static boolean areCallNotificationsDisabled(Context context) {
|
||||
return !TextSecurePreferences.isCallNotificationsEnabled(context);
|
||||
}
|
||||
|
||||
private static boolean isCallChannelInvalid(Context context) {
|
||||
return !NotificationChannels.isCallsChannelValid(context);
|
||||
}
|
||||
|
||||
private static boolean isBackgroundRestricted(Context context) {
|
||||
return Build.VERSION.SDK_INT >= 28 && DeviceProperties.isBackgroundRestricted(context);
|
||||
}
|
||||
|
||||
private static int getCallNotificationSettingsBitmask(@NonNull Context context) {
|
||||
int bitmask = 0;
|
||||
|
||||
if (areNotificationsDisabled(context)) {
|
||||
bitmask |= NOTIFICATIONS_DISABLED;
|
||||
}
|
||||
|
||||
if (areCallNotificationsDisabled(context)) {
|
||||
bitmask |= CALL_NOTIFICATIONS_DISABLED;
|
||||
}
|
||||
|
||||
if (isCallChannelInvalid(context)) {
|
||||
bitmask |= CALL_CHANNEL_INVALID;
|
||||
}
|
||||
|
||||
if (isBackgroundRestricted(context)) {
|
||||
bitmask |= BACKGROUND_RESTRICTED;
|
||||
}
|
||||
|
||||
return bitmask;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user