Improve Call Notification UX when things don't go as planned.
This commit is contained in:
parent
b053fbc4a7
commit
d8dead82b6
15 changed files with 442 additions and 27 deletions
|
@ -67,6 +67,7 @@ public interface BindableConversationItem extends Unbindable {
|
||||||
void onSafetyNumberLearnMoreClicked(@NonNull Recipient recipient);
|
void onSafetyNumberLearnMoreClicked(@NonNull Recipient recipient);
|
||||||
void onJoinGroupCallClicked();
|
void onJoinGroupCallClicked();
|
||||||
void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId);
|
void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId);
|
||||||
|
void onEnableCallNotificationsClicked();
|
||||||
|
|
||||||
/** @return true if handled, false if you want to let the normal url handling continue */
|
/** @return true if handled, false if you want to let the normal url handling continue */
|
||||||
boolean onUrlClicked(@NonNull String url);
|
boolean onUrlClicked(@NonNull String url);
|
||||||
|
|
|
@ -88,6 +88,7 @@ import org.thoughtcrime.securesms.contactshare.SharedContactDetailsActivity;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickListener;
|
import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickListener;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter.StickyHeaderViewHolder;
|
import org.thoughtcrime.securesms.conversation.ConversationAdapter.StickyHeaderViewHolder;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
|
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.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
|
@ -1558,6 +1559,23 @@ public class ConversationFragment extends LoggingFragment {
|
||||||
public void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId) {
|
public void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId) {
|
||||||
GroupLinkInviteFriendsBottomSheetDialogFragment.show(requireActivity().getSupportFragmentManager(), 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
|
@Override
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.BindableConversationItem;
|
import org.thoughtcrime.securesms.BindableConversationItem;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.VerifyIdentityActivity;
|
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.IdentityDatabase.IdentityRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
||||||
import org.thoughtcrime.securesms.database.model.LiveUpdateMessage;
|
import org.thoughtcrime.securesms.database.model.LiveUpdateMessage;
|
||||||
|
@ -302,6 +303,14 @@ public final class ConversationUpdateItem extends FrameLayout
|
||||||
eventListener.onInviteFriendsToGroupClicked(conversationRecipient.requireGroupId().requireV2());
|
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 {
|
} else {
|
||||||
actionButton.setVisibility(GONE);
|
actionButton.setVisibility(GONE);
|
||||||
actionButton.setOnClickListener(null);
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import android.annotation.TargetApi;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationChannelGroup;
|
import android.app.NotificationChannelGroup;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
@ -13,6 +14,7 @@ import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -219,10 +221,15 @@ public class NotificationChannels {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
|
try {
|
||||||
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId);
|
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
|
||||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId);
|
||||||
context.startActivity(intent);
|
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName());
|
||||||
|
context.startActivity(intent);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Log.w(TAG, "Channel settings activity not found", e);
|
||||||
|
Toast.makeText(context, R.string.NotificationChannels__no_activity_available_to_open_notification_channel_settings, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -413,6 +420,16 @@ public class NotificationChannels {
|
||||||
return group != null && !group.isBlocked();
|
return group != null && !group.isBlocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isCallsChannelValid(@NonNull Context context) {
|
||||||
|
if (!supported()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationManager notificationManager = ServiceUtil.getNotificationManager(context);
|
||||||
|
NotificationChannel channel = notificationManager.getNotificationChannel(CALLS);
|
||||||
|
|
||||||
|
return channel != null && channel.getImportance() == NotificationManager.IMPORTANCE_HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not notifications for the entire app are enabled.
|
* Whether or not notifications for the entire app are enabled.
|
||||||
|
|
|
@ -31,10 +31,8 @@ import org.signal.ringrtc.HttpHeader;
|
||||||
import org.signal.ringrtc.Remote;
|
import org.signal.ringrtc.Remote;
|
||||||
import org.signal.storageservice.protos.groups.GroupExternalCredential;
|
import org.signal.storageservice.protos.groups.GroupExternalCredential;
|
||||||
import org.signal.zkgroup.VerificationFailedException;
|
import org.signal.zkgroup.VerificationFailedException;
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
|
||||||
import org.thoughtcrime.securesms.BuildConfig;
|
import org.thoughtcrime.securesms.BuildConfig;
|
||||||
import org.thoughtcrime.securesms.WebRtcCallActivity;
|
import org.thoughtcrime.securesms.WebRtcCallActivity;
|
||||||
import org.thoughtcrime.securesms.components.sensors.DeviceOrientationMonitor;
|
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
|
@ -57,6 +55,7 @@ import org.thoughtcrime.securesms.service.webrtc.IdleActionProcessor;
|
||||||
import org.thoughtcrime.securesms.service.webrtc.WebRtcInteractor;
|
import org.thoughtcrime.securesms.service.webrtc.WebRtcInteractor;
|
||||||
import org.thoughtcrime.securesms.service.webrtc.WebRtcUtil;
|
import org.thoughtcrime.securesms.service.webrtc.WebRtcUtil;
|
||||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
||||||
|
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||||
import org.thoughtcrime.securesms.util.BubbleUtil;
|
import org.thoughtcrime.securesms.util.BubbleUtil;
|
||||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
|
@ -90,10 +89,14 @@ import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.thoughtcrime.securesms.events.WebRtcViewModel.GroupCallState.IDLE;
|
||||||
|
import static org.thoughtcrime.securesms.events.WebRtcViewModel.State.CALL_INCOMING;
|
||||||
|
|
||||||
public class WebRtcCallService extends Service implements CallManager.Observer,
|
public class WebRtcCallService extends Service implements CallManager.Observer,
|
||||||
BluetoothStateManager.BluetoothStateListener,
|
BluetoothStateManager.BluetoothStateListener,
|
||||||
CameraEventListener,
|
CameraEventListener,
|
||||||
GroupCall.Observer
|
GroupCall.Observer,
|
||||||
|
AppForegroundObserver.Listener
|
||||||
{
|
{
|
||||||
|
|
||||||
private static final String TAG = Log.tag(WebRtcCallService.class);
|
private static final String TAG = Log.tag(WebRtcCallService.class);
|
||||||
|
@ -276,6 +279,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
|
||||||
new SignalAudioManager(this),
|
new SignalAudioManager(this),
|
||||||
bluetoothStateManager,
|
bluetoothStateManager,
|
||||||
this,
|
this,
|
||||||
|
this,
|
||||||
this);
|
this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -479,15 +483,16 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
|
||||||
return listenableFutureTask;
|
return listenableFutureTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startCallCardActivityIfPossible() {
|
public boolean startCallCardActivityIfPossible() {
|
||||||
if (Build.VERSION.SDK_INT >= 29 && !ApplicationDependencies.getAppForegroundObserver().isForegrounded()) {
|
if (Build.VERSION.SDK_INT >= 29 && !ApplicationDependencies.getAppForegroundObserver().isForegrounded()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent activityIntent = new Intent();
|
Intent activityIntent = new Intent();
|
||||||
activityIntent.setClass(this, WebRtcCallActivity.class);
|
activityIntent.setClass(this, WebRtcCallActivity.class);
|
||||||
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivity(activityIntent);
|
startActivity(activityIntent);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull OfferMessage.Type getOfferTypeFromCallMediaType(@NonNull CallManager.CallMediaType mediaType) {
|
private static @NonNull OfferMessage.Type getOfferTypeFromCallMediaType(@NonNull CallManager.CallMediaType mediaType) {
|
||||||
|
@ -516,6 +521,18 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onForeground() {
|
||||||
|
WebRtcViewModel.State callState = serviceState.getCallInfoState().getCallState();
|
||||||
|
if (callState == CALL_INCOMING && serviceState.getCallInfoState().getGroupCallState() == IDLE) {
|
||||||
|
startCallCardActivityIfPossible();
|
||||||
|
}
|
||||||
|
ApplicationDependencies.getAppForegroundObserver().removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackground() { }
|
||||||
|
|
||||||
private static class WiredHeadsetStateReceiver extends BroadcastReceiver {
|
private static class WiredHeadsetStateReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
|
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.annotation.NonNull;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.signal.ringrtc.CallException;
|
import org.signal.ringrtc.CallException;
|
||||||
import org.signal.ringrtc.CallManager;
|
import org.signal.ringrtc.CallManager;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||||
import org.thoughtcrime.securesms.ringrtc.CallState;
|
import org.thoughtcrime.securesms.ringrtc.CallState;
|
||||||
import org.thoughtcrime.securesms.ringrtc.Camera;
|
import org.thoughtcrime.securesms.ringrtc.Camera;
|
||||||
|
@ -37,6 +38,7 @@ public class CallSetupActionProcessorDelegate extends WebRtcActionProcessor {
|
||||||
|
|
||||||
RemotePeer activePeer = currentState.getCallInfoState().requireActivePeer();
|
RemotePeer activePeer = currentState.getCallInfoState().requireActivePeer();
|
||||||
|
|
||||||
|
ApplicationDependencies.getAppForegroundObserver().removeListener(webRtcInteractor.getForegroundListener());
|
||||||
webRtcInteractor.startAudioCommunication(activePeer.getState() == CallState.REMOTE_RINGING);
|
webRtcInteractor.startAudioCommunication(activePeer.getState() == CallState.REMOTE_RINGING);
|
||||||
webRtcInteractor.setWantsBluetoothConnection(true);
|
webRtcInteractor.setWantsBluetoothConnection(true);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.signal.ringrtc.CallId;
|
||||||
import org.thoughtcrime.securesms.components.webrtc.OrientationAwareVideoSink;
|
import org.thoughtcrime.securesms.components.webrtc.OrientationAwareVideoSink;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.events.CallParticipant;
|
import org.thoughtcrime.securesms.events.CallParticipant;
|
||||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||||
import org.thoughtcrime.securesms.notifications.DoNotDisturbUtil;
|
import org.thoughtcrime.securesms.notifications.DoNotDisturbUtil;
|
||||||
|
@ -157,7 +158,11 @@ public class IncomingCallActionProcessor extends DeviceAwareActionProcessor {
|
||||||
|
|
||||||
boolean shouldDisturbUserWithCall = DoNotDisturbUtil.shouldDisturbUserWithCall(context.getApplicationContext(), recipient);
|
boolean shouldDisturbUserWithCall = DoNotDisturbUtil.shouldDisturbUserWithCall(context.getApplicationContext(), recipient);
|
||||||
if (shouldDisturbUserWithCall) {
|
if (shouldDisturbUserWithCall) {
|
||||||
webRtcInteractor.startWebRtcCallActivityIfPossible();
|
boolean started = webRtcInteractor.startWebRtcCallActivityIfPossible();
|
||||||
|
if (!started) {
|
||||||
|
Log.i(TAG, "Unable to start call activity due to OS version or not being in the foreground");
|
||||||
|
ApplicationDependencies.getAppForegroundObserver().addListener(webRtcInteractor.getForegroundListener());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webRtcInteractor.initializeAudioForCall();
|
webRtcInteractor.initializeAudioForCall();
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.signal.ringrtc.CallId;
|
||||||
import org.signal.ringrtc.GroupCall;
|
import org.signal.ringrtc.GroupCall;
|
||||||
import org.thoughtcrime.securesms.components.sensors.Orientation;
|
import org.thoughtcrime.securesms.components.sensors.Orientation;
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.events.CallParticipant;
|
import org.thoughtcrime.securesms.events.CallParticipant;
|
||||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
|
@ -723,6 +724,8 @@ public abstract class WebRtcActionProcessor {
|
||||||
return currentState;
|
return currentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ApplicationDependencies.getAppForegroundObserver().removeListener(webRtcInteractor.getForegroundListener());
|
||||||
|
|
||||||
webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING);
|
webRtcInteractor.updatePhoneState(LockManager.PhoneState.PROCESSING);
|
||||||
webRtcInteractor.stopForegroundService();
|
webRtcInteractor.stopForegroundService();
|
||||||
boolean playDisconnectSound = (activePeer.getState() == CallState.DIALING) ||
|
boolean playDisconnectSound = (activePeer.getState() == CallState.DIALING) ||
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.ringrtc.CameraEventListener;
|
||||||
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
|
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
|
||||||
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
||||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
||||||
|
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||||
import org.thoughtcrime.securesms.webrtc.audio.BluetoothStateManager;
|
import org.thoughtcrime.securesms.webrtc.audio.BluetoothStateManager;
|
||||||
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger;
|
import org.thoughtcrime.securesms.webrtc.audio.OutgoingRinger;
|
||||||
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
|
import org.thoughtcrime.securesms.webrtc.audio.SignalAudioManager;
|
||||||
|
@ -29,13 +30,14 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public class WebRtcInteractor {
|
public class WebRtcInteractor {
|
||||||
|
|
||||||
@NonNull private final WebRtcCallService webRtcCallService;
|
@NonNull private final WebRtcCallService webRtcCallService;
|
||||||
@NonNull private final CallManager callManager;
|
@NonNull private final CallManager callManager;
|
||||||
@NonNull private final LockManager lockManager;
|
@NonNull private final LockManager lockManager;
|
||||||
@NonNull private final SignalAudioManager audioManager;
|
@NonNull private final SignalAudioManager audioManager;
|
||||||
@NonNull private final BluetoothStateManager bluetoothStateManager;
|
@NonNull private final BluetoothStateManager bluetoothStateManager;
|
||||||
@NonNull private final CameraEventListener cameraEventListener;
|
@NonNull private final CameraEventListener cameraEventListener;
|
||||||
@NonNull private final GroupCall.Observer groupCallObserver;
|
@NonNull private final GroupCall.Observer groupCallObserver;
|
||||||
|
@NonNull private final AppForegroundObserver.Listener foregroundListener;
|
||||||
|
|
||||||
public WebRtcInteractor(@NonNull WebRtcCallService webRtcCallService,
|
public WebRtcInteractor(@NonNull WebRtcCallService webRtcCallService,
|
||||||
@NonNull CallManager callManager,
|
@NonNull CallManager callManager,
|
||||||
|
@ -43,7 +45,8 @@ public class WebRtcInteractor {
|
||||||
@NonNull SignalAudioManager audioManager,
|
@NonNull SignalAudioManager audioManager,
|
||||||
@NonNull BluetoothStateManager bluetoothStateManager,
|
@NonNull BluetoothStateManager bluetoothStateManager,
|
||||||
@NonNull CameraEventListener cameraEventListener,
|
@NonNull CameraEventListener cameraEventListener,
|
||||||
@NonNull GroupCall.Observer groupCallObserver)
|
@NonNull GroupCall.Observer groupCallObserver,
|
||||||
|
@NonNull AppForegroundObserver.Listener foregroundListener)
|
||||||
{
|
{
|
||||||
this.webRtcCallService = webRtcCallService;
|
this.webRtcCallService = webRtcCallService;
|
||||||
this.callManager = callManager;
|
this.callManager = callManager;
|
||||||
|
@ -52,6 +55,7 @@ public class WebRtcInteractor {
|
||||||
this.bluetoothStateManager = bluetoothStateManager;
|
this.bluetoothStateManager = bluetoothStateManager;
|
||||||
this.cameraEventListener = cameraEventListener;
|
this.cameraEventListener = cameraEventListener;
|
||||||
this.groupCallObserver = groupCallObserver;
|
this.groupCallObserver = groupCallObserver;
|
||||||
|
this.foregroundListener = foregroundListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull CameraEventListener getCameraEventListener() {
|
@NonNull CameraEventListener getCameraEventListener() {
|
||||||
|
@ -70,6 +74,10 @@ public class WebRtcInteractor {
|
||||||
return groupCallObserver;
|
return groupCallObserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull AppForegroundObserver.Listener getForegroundListener() {
|
||||||
|
return foregroundListener;
|
||||||
|
}
|
||||||
|
|
||||||
void setWantsBluetoothConnection(boolean enabled) {
|
void setWantsBluetoothConnection(boolean enabled) {
|
||||||
bluetoothStateManager.setWantsConnection(enabled);
|
bluetoothStateManager.setWantsConnection(enabled);
|
||||||
}
|
}
|
||||||
|
@ -118,8 +126,8 @@ public class WebRtcInteractor {
|
||||||
webRtcCallService.insertMissedCall(remotePeer, signal, timestamp, isVideoOffer);
|
webRtcCallService.insertMissedCall(remotePeer, signal, timestamp, isVideoOffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startWebRtcCallActivityIfPossible() {
|
boolean startWebRtcCallActivityIfPossible() {
|
||||||
webRtcCallService.startCallCardActivityIfPossible();
|
return webRtcCallService.startCallCardActivityIfPossible();
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerPowerButtonReceiver() {
|
void registerPowerButtonReceiver() {
|
||||||
|
|
|
@ -987,6 +987,10 @@ public class TextSecurePreferences {
|
||||||
return getBooleanPreference(context, NOTIFICATION_PREF, true);
|
return getBooleanPreference(context, NOTIFICATION_PREF, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setCallNotificationsEnabled(Context context, boolean enabled) {
|
||||||
|
setBooleanPreference(context, CALL_NOTIFICATIONS_PREF, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isCallNotificationsEnabled(Context context) {
|
public static boolean isCallNotificationsEnabled(Context context) {
|
||||||
return getBooleanPreference(context, CALL_NOTIFICATIONS_PREF, true);
|
return getBooleanPreference(context, CALL_NOTIFICATIONS_PREF, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@color/signal_icon_tint_primary"
|
android:fillColor="#000000"
|
||||||
android:pathData="M9.172,18.5l-6.188,-6.187l1.061,-1.061l5.127,5.127l10.783,-10.784l1.061,1.061l-11.844,11.844z"/>
|
android:pathData="M9.172,18.5l-6.188,-6.187l1.061,-1.061l5.127,5.127l10.783,-10.784l1.061,1.061l-11.844,11.844z"/>
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@color/core_white"
|
android:fillColor="#ffffff"
|
||||||
android:pathData="M12,2.5A9.5,9.5 0,1 1,2.5 12,9.511 9.511,0 0,1 12,2.5M12,1A11,11 0,1 0,23 12,11 11,0 0,0 12,1ZM12,8.5A1.5,1.5 0,0 0,13.5 7a1.5,1.5 0,1 0,-2.56 1.06A1.435,1.435 0,0 0,12 8.5ZM13,16.5L13,10L9.5,10v1.5h2v5L9,16.5L9,18h6L15,16.5Z" />
|
android:pathData="M12,2.5A9.5,9.5 0,1 1,2.5 12,9.511 9.511,0 0,1 12,2.5M12,1A11,11 0,1 0,23 12,11 11,0 0,0 12,1ZM12,8.5A1.5,1.5 0,0 0,13.5 7a1.5,1.5 0,1 0,-2.56 1.06A1.435,1.435 0,0 0,12 8.5ZM13,16.5L13,10L9.5,10v1.5h2v5L9,16.5L9,18h6L15,16.5Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.gridlayout.widget.GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="?attr/dialogPreferredPadding"
|
||||||
|
app:alignmentMode="alignBounds"
|
||||||
|
app:columnCount="2">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/enable_call_notification_settings_dialog_system_all_configured"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/EnableCallNotificationSettingsDialog__everything_looks_good_now"
|
||||||
|
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_columnSpan="2" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/enable_call_notification_settings_dialog_system_setting_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:layout_gravity="center_vertical"
|
||||||
|
app:srcCompat="@drawable/ic_info_white_24"
|
||||||
|
app:tint="@color/signal_alert_primary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/enable_call_notification_settings_dialog_system_setting_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:text="@string/EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_here_and_turn_on_show_notifications"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
|
app:layout_columnWeight="1"
|
||||||
|
app:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/enable_call_notification_settings_dialog_channel_setting_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:layout_gravity="center_vertical"
|
||||||
|
app:srcCompat="@drawable/ic_info_white_24"
|
||||||
|
app:tint="@color/signal_alert_primary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/enable_call_notification_settings_dialog_channel_setting_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:text="@string/EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_here_and_turn_on_notifications"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
|
app:layout_columnWeight="1"
|
||||||
|
app:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/enable_call_notification_settings_dialog_background_restricted_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
app:layout_gravity="center_vertical"
|
||||||
|
app:srcCompat="@drawable/ic_info_white_24"
|
||||||
|
app:tint="@color/signal_alert_primary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/enable_call_notification_settings_dialog_background_restricted_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:text="@string/EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_here_and_enable_background_activity_in_battery_settings"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
|
app:layout_columnWeight="1"
|
||||||
|
app:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
</androidx.gridlayout.widget.GridLayout>
|
|
@ -1722,7 +1722,7 @@
|
||||||
<string name="NotificationChannel_group_messages">Messages</string>
|
<string name="NotificationChannel_group_messages">Messages</string>
|
||||||
<string name="NotificationChannel_missing_display_name">Unknown</string>
|
<string name="NotificationChannel_missing_display_name">Unknown</string>
|
||||||
<string name="NotificationChannel_voice_notes">Voice Notes</string>
|
<string name="NotificationChannel_voice_notes">Voice Notes</string>
|
||||||
|
<string name="NotificationChannels__no_activity_available_to_open_notification_channel_settings">No activity available to open notification channel settings.</string>
|
||||||
<!-- ProfileEditNameFragment -->
|
<!-- ProfileEditNameFragment -->
|
||||||
|
|
||||||
<!-- QuickResponseService -->
|
<!-- QuickResponseService -->
|
||||||
|
@ -1871,6 +1871,7 @@
|
||||||
<string name="ConversationUpdateItem_return_to_call">Return to call</string>
|
<string name="ConversationUpdateItem_return_to_call">Return to call</string>
|
||||||
<string name="ConversationUpdateItem_call_is_full">Call is full</string>
|
<string name="ConversationUpdateItem_call_is_full">Call is full</string>
|
||||||
<string name="ConversationUpdateItem_invite_friends">Invite friends</string>
|
<string name="ConversationUpdateItem_invite_friends">Invite friends</string>
|
||||||
|
<string name="ConversationUpdateItem_enable_call_notifications">Enable Call Notifications</string>
|
||||||
|
|
||||||
<!-- audio_view -->
|
<!-- audio_view -->
|
||||||
<string name="audio_view__play_pause_accessibility_description">Play … Pause</string>
|
<string name="audio_view__play_pause_accessibility_description">Play … Pause</string>
|
||||||
|
@ -1899,6 +1900,19 @@
|
||||||
<string name="safety_number_change_dialog__view">View</string>
|
<string name="safety_number_change_dialog__view">View</string>
|
||||||
<string name="safety_number_change_dialog__previous_verified">Previous verified</string>
|
<string name="safety_number_change_dialog__previous_verified">Previous verified</string>
|
||||||
|
|
||||||
|
<!-- EnableCallNotificationSettingsDialog__call_notifications_checklist -->
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__call_notifications_enabled">Call notifications enabled.</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__enable_call_notifications">Enable call notifications</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__enable_background_activity">Enable background activity</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__everything_looks_good_now">Everything looks good now!</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_here_and_turn_on_show_notifications">To receive call notifications, tap here and turn on \"Show notifications.\"</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_here_and_turn_on_notifications">To receive call notifications, tap here and turn on notifications and make sure Sound and Pop-up are enabled.</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_here_and_enable_background_activity_in_battery_settings">To receive call notifications, tap here and enable background activity in \"Battery\" settings. </string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__settings">Settings</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_settings_and_turn_on_show_notifications">To receive call notifications, tap Settings and turn on \"Show notifications.\"</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_settings_and_turn_on_notifications">To receive call notifications, tap Settings and turn on notifications and make sure Sound and Pop-up are enabled.</string>
|
||||||
|
<string name="EnableCallNotificationSettingsDialog__to_receive_call_notifications_tap_settings_and_enable_background_activity_in_battery_settings">To receive call notifications, tap Settings and enable background activity in \"Battery\" settings.</string>
|
||||||
|
|
||||||
<!-- country_selection_fragment -->
|
<!-- country_selection_fragment -->
|
||||||
<string name="country_selection_fragment__loading_countries">Loading countries…</string>
|
<string name="country_selection_fragment__loading_countries">Loading countries…</string>
|
||||||
<string name="country_selection_fragment__search">Search</string>
|
<string name="country_selection_fragment__search">Search</string>
|
||||||
|
|
Loading…
Add table
Reference in a new issue