diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 4fd89f8a776cf6345fb96e652612ae25e9214f17..83bef27e7bd094dc5368b2b0e7a34638d58e9da8 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -78,6 +78,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -114,7 +115,7 @@ public class NotificationService { private static final String INCOMING_CALLS_NOTIFICATION_CHANNEL = "incoming_calls_channel"; private static final String INCOMING_CALLS_NOTIFICATION_CHANNEL_PREFIX = "incoming_calls_channel#"; - private static final String MESSAGES_NOTIFICATION_CHANNEL = "messages"; + public static final String MESSAGES_NOTIFICATION_CHANNEL = "messages"; NotificationService(final XmppConnectionService service) { this.mXmppConnectionService = service; @@ -229,25 +230,8 @@ public class NotificationService { missedCallsChannel.setGroup("calls"); notificationManager.createNotificationChannel(missedCallsChannel); - final NotificationChannel messagesChannel = - new NotificationChannel( - MESSAGES_NOTIFICATION_CHANNEL, - c.getString(R.string.messages_channel_name), - NotificationManager.IMPORTANCE_HIGH); - messagesChannel.setShowBadge(true); - messagesChannel.setSound( - RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), - new AudioAttributes.Builder() - .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) - .setUsage(AudioAttributes.USAGE_NOTIFICATION) - .build()); - messagesChannel.setLightColor(LED_COLOR); - final int dat = 70; - final long[] pattern = {0, 3 * dat, dat, dat}; - messagesChannel.setVibrationPattern(pattern); - messagesChannel.enableVibration(true); - messagesChannel.enableLights(true); - messagesChannel.setGroup("chats"); + final var messagesChannel = + prepareMessagesChannel(mXmppConnectionService, MESSAGES_NOTIFICATION_CHANNEL); notificationManager.createNotificationChannel(messagesChannel); final NotificationChannel silentMessagesChannel = new NotificationChannel( @@ -278,6 +262,41 @@ public class NotificationService { notificationManager.createNotificationChannel(deliveryFailedChannel); } + @RequiresApi(api = Build.VERSION_CODES.R) + public static void createConversationChannel( + final Context context, final ShortcutInfoCompat shortcut) { + final var messagesChannel = prepareMessagesChannel(context, UUID.randomUUID().toString()); + messagesChannel.setName(shortcut.getShortLabel()); + messagesChannel.setConversationId(MESSAGES_NOTIFICATION_CHANNEL, shortcut.getId()); + final var notificationManager = context.getSystemService(NotificationManager.class); + notificationManager.createNotificationChannel(messagesChannel); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + private static NotificationChannel prepareMessagesChannel( + final Context context, final String id) { + final NotificationChannel messagesChannel = + new NotificationChannel( + id, + context.getString(R.string.messages_channel_name), + NotificationManager.IMPORTANCE_HIGH); + messagesChannel.setShowBadge(true); + messagesChannel.setSound( + RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION), + new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) + .setUsage(AudioAttributes.USAGE_NOTIFICATION) + .build()); + messagesChannel.setLightColor(LED_COLOR); + final int dat = 70; + final long[] pattern = {0, 3 * dat, dat, dat}; + messagesChannel.setVibrationPattern(pattern); + messagesChannel.enableVibration(true); + messagesChannel.enableLights(true); + messagesChannel.setGroup("chats"); + return messagesChannel; + } + @RequiresApi(api = Build.VERSION_CODES.O) private static void createInitialIncomingCallChannelIfNecessary(final Context context) { final var currentIteration = getCurrentIncomingCallChannelIteration(context); diff --git a/src/main/java/eu/siacs/conversations/services/ShortcutService.java b/src/main/java/eu/siacs/conversations/services/ShortcutService.java index ef208d690fb174aee109ff1072f2b0c16f4cdd77..b2a3cce750b9d19df4b78fd204497917ea809996 100644 --- a/src/main/java/eu/siacs/conversations/services/ShortcutService.java +++ b/src/main/java/eu/siacs/conversations/services/ShortcutService.java @@ -93,6 +93,12 @@ public class ShortcutService { } } + public ShortcutInfoCompat getShortcutInfo(final Contact contact) { + final var conversation = xmppConnectionService.find(contact); + final var uuid = conversation == null ? null : conversation.getUuid(); + return getShortcutInfo(contact, uuid); + } + public ShortcutInfoCompat getShortcutInfo(final Contact contact, final String conversation) { final ShortcutInfoCompat.Builder builder = new ShortcutInfoCompat.Builder(xmppConnectionService, getShortcutId(contact)) @@ -199,9 +205,7 @@ public class ShortcutService { public Intent createShortcut(final Contact contact, final boolean legacy) { Intent intent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !legacy) { - final var conversation = xmppConnectionService.find(contact); - final var uuid = conversation == null ? null : conversation.getUuid(); - final var shortcut = getShortcutInfo(contact, uuid); + final var shortcut = getShortcutInfo(contact); intent = ShortcutManagerCompat.createShortcutResultIntent( xmppConnectionService, shortcut); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index a5511bd23c0c9189fb44dd9f3883fa9a49366aff..832c6c8d6ce875386d57ecb68be5a67f4aa2d699 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2302,6 +2302,7 @@ public class XmppConnectionService extends Service { Config.LOGTAG, account.getJid().asBareJid() + ": pushing bookmark via Bookmarks 2"); final Element item = mIqGenerator.publishBookmarkItem(bookmark); + Log.d(Config.LOGTAG, "publishing: " + item.toString()); pushNodeAndEnforcePublishOptions( account, Namespace.BOOKMARKS2, @@ -2873,6 +2874,7 @@ public class XmppConnectionService extends Service { existing.getMode() == Conversational.MODE_MULTI, null)); this.conversations.add(existing); + // TODO push bookmark updateConversationUi(); return existing; } diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 2cd9cb5d32305f25eed9023339173deb5c097d06..8a1a0a1335c07c87541babff4d506ddeeb55b167 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -1,9 +1,13 @@ package eu.siacs.conversations.ui; +import static eu.siacs.conversations.entities.Bookmark.printableValue; +import static eu.siacs.conversations.utils.StringUtils.changed; + import android.app.Activity; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.os.Bundle; import android.text.Editable; import android.text.SpannableStringBuilder; @@ -14,20 +18,14 @@ import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Toast; - +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.databinding.DataBindingUtil; - -import java.util.Collections; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import eu.siacs.conversations.Config; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import eu.siacs.conversations.R; import eu.siacs.conversations.databinding.ActivityMucDetailsBinding; -import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Conversational; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.User; import eu.siacs.conversations.services.XmppConnectionService; @@ -50,14 +48,19 @@ import eu.siacs.conversations.utils.StringUtils; import eu.siacs.conversations.utils.StylingHelper; import eu.siacs.conversations.utils.XmppUri; import eu.siacs.conversations.xmpp.Jid; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import me.drakeet.support.toast.ToastCompat; -import static eu.siacs.conversations.entities.Bookmark.printableValue; -import static eu.siacs.conversations.utils.StringUtils.changed; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; - -public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnMucRosterUpdate, XmppConnectionService.OnAffiliationChanged, XmppConnectionService.OnConfigurationPushed, XmppConnectionService.OnRoomDestroy, TextWatcher, OnMediaLoaded { +public class ConferenceDetailsActivity extends XmppActivity + implements OnConversationUpdate, + OnMucRosterUpdate, + XmppConnectionService.OnAffiliationChanged, + XmppConnectionService.OnConfigurationPushed, + XmppConnectionService.OnRoomDestroy, + TextWatcher, + OnMediaLoaded { public static final String ACTION_VIEW_MUC = "view_muc"; private Conversation mConversation; @@ -68,26 +71,25 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers private boolean mAdvancedMode = false; - private final UiCallback renameCallback = new UiCallback() { - @Override - public void success(Conversation object) { - displayToast(getString(R.string.your_nick_has_been_changed)); - runOnUiThread(() -> { - updateView(); - }); - - } - - @Override - public void error(final int errorCode, Conversation object) { - displayToast(getString(errorCode)); - } + private final UiCallback renameCallback = + new UiCallback() { + @Override + public void success(Conversation object) { + displayToast(getString(R.string.your_nick_has_been_changed)); + runOnUiThread( + () -> { + updateView(); + }); + } - @Override - public void userInputRequired(PendingIntent pi, Conversation object) { + @Override + public void error(final int errorCode, Conversation object) { + displayToast(getString(errorCode)); + } - } - }; + @Override + public void userInputRequired(PendingIntent pi, Conversation object) {} + }; public static void open(final Activity activity, final Conversation conversation) { Intent intent = new Intent(activity, ConferenceDetailsActivity.class); @@ -96,37 +98,45 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers activity.startActivity(intent); } - private final OnClickListener mNotifyStatusClickListener = new OnClickListener() { - @Override - public void onClick(View v) { - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ConferenceDetailsActivity.this); - builder.setTitle(R.string.pref_notification_settings); - String[] choices = { - getString(R.string.notify_on_all_messages), - getString(R.string.notify_only_when_highlighted), - getString(R.string.notify_never) - }; - final AtomicInteger choice; - if (mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0) == Long.MAX_VALUE) { - choice = new AtomicInteger(2); - } else { - choice = new AtomicInteger(mConversation.alwaysNotify() ? 0 : 1); - } - builder.setSingleChoiceItems(choices, choice.get(), (dialog, which) -> choice.set(which)); - builder.setNegativeButton(R.string.cancel, null); - builder.setPositiveButton(R.string.ok, (dialog, which) -> { - if (choice.get() == 2) { - mConversation.setMutedTill(Long.MAX_VALUE); - } else { - mConversation.setMutedTill(0); - mConversation.setAttribute(Conversation.ATTRIBUTE_ALWAYS_NOTIFY, String.valueOf(choice.get() == 0)); + private final OnClickListener mNotifyStatusClickListener = + new OnClickListener() { + @Override + public void onClick(View v) { + final MaterialAlertDialogBuilder builder = + new MaterialAlertDialogBuilder(ConferenceDetailsActivity.this); + builder.setTitle(R.string.pref_notification_settings); + String[] choices = { + getString(R.string.notify_on_all_messages), + getString(R.string.notify_only_when_highlighted), + getString(R.string.notify_never) + }; + final AtomicInteger choice; + if (mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0) + == Long.MAX_VALUE) { + choice = new AtomicInteger(2); + } else { + choice = new AtomicInteger(mConversation.alwaysNotify() ? 0 : 1); + } + builder.setSingleChoiceItems( + choices, choice.get(), (dialog, which) -> choice.set(which)); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton( + R.string.ok, + (dialog, which) -> { + if (choice.get() == 2) { + mConversation.setMutedTill(Long.MAX_VALUE); + } else { + mConversation.setMutedTill(0); + mConversation.setAttribute( + Conversation.ATTRIBUTE_ALWAYS_NOTIFY, + String.valueOf(choice.get() == 0)); + } + xmppConnectionService.updateConversation(mConversation); + updateView(); + }); + builder.create().show(); } - xmppConnectionService.updateConversation(mConversation); - updateView(); - }); - builder.create().show(); - } - }; + }; private final OnClickListener mChangeConferenceSettings = new OnClickListener() { @@ -185,37 +195,56 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.changeConferenceButton.setOnClickListener(this.mChangeConferenceSettings); setSupportActionBar(binding.toolbar); configureActionBar(getSupportActionBar()); - this.binding.editNickButton.setOnClickListener(v -> quickEdit(mConversation.getMucOptions().getActualNick(), - R.string.nickname, - value -> { - if (xmppConnectionService.renameInMuc(mConversation, value, renameCallback)) { - return null; - } else { - return getString(R.string.invalid_muc_nick); - } - })); + this.binding.editNickButton.setOnClickListener( + v -> + quickEdit( + mConversation.getMucOptions().getActualNick(), + R.string.nickname, + value -> { + if (xmppConnectionService.renameInMuc( + mConversation, value, renameCallback)) { + return null; + } else { + return getString(R.string.invalid_muc_nick); + } + })); this.mAdvancedMode = getPreferences().getBoolean("advanced_muc_mode", false); this.binding.mucInfoMore.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE); this.binding.notificationStatusButton.setOnClickListener(this.mNotifyStatusClickListener); - this.binding.yourPhoto.setOnClickListener(v -> { - final MucOptions mucOptions = mConversation.getMucOptions(); - if (!mucOptions.hasVCards()) { - Toast.makeText(this, R.string.host_does_not_support_group_chat_avatars, Toast.LENGTH_SHORT).show(); - return; - } - if (!mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER)) { - Toast.makeText(this, R.string.only_the_owner_can_change_group_chat_avatar, Toast.LENGTH_SHORT).show(); - return; - } - final Intent intent = new Intent(this, PublishGroupChatProfilePictureActivity.class); - intent.putExtra("uuid", mConversation.getUuid()); - startActivity(intent); - }); - this.binding.editMucNameButton.setContentDescription(getString(R.string.edit_name_and_topic)); + this.binding.yourPhoto.setOnClickListener( + v -> { + final MucOptions mucOptions = mConversation.getMucOptions(); + if (!mucOptions.hasVCards()) { + Toast.makeText( + this, + R.string.host_does_not_support_group_chat_avatars, + Toast.LENGTH_SHORT) + .show(); + return; + } + if (!mucOptions + .getSelf() + .getAffiliation() + .ranks(MucOptions.Affiliation.OWNER)) { + Toast.makeText( + this, + R.string.only_the_owner_can_change_group_chat_avatar, + Toast.LENGTH_SHORT) + .show(); + return; + } + final Intent intent = + new Intent(this, PublishGroupChatProfilePictureActivity.class); + intent.putExtra("uuid", mConversation.getUuid()); + startActivity(intent); + }); + this.binding.editMucNameButton.setContentDescription( + getString(R.string.edit_name_and_topic)); this.binding.editMucNameButton.setOnClickListener(this::onMucEditButtonClicked); this.binding.mucEditTitle.addTextChangedListener(this); this.binding.mucEditSubject.addTextChangedListener(this); - this.binding.mucEditSubject.addTextChangedListener(new StylingHelper.MessageEditorStyler(this.binding.mucEditSubject)); + this.binding.mucEditSubject.addTextChangedListener( + new StylingHelper.MessageEditorStyler(this.binding.mucEditSubject)); this.mMediaAdapter = new MediaAdapter(this, R.dimen.media_size); this.mUserPreviewAdapter = new UserPreviewAdapter(); this.binding.media.setAdapter(mMediaAdapter); @@ -223,17 +252,19 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers GridManager.setupLayoutManager(this, this.binding.media, R.dimen.media_size); GridManager.setupLayoutManager(this, this.binding.users, R.dimen.media_size); this.binding.invite.setOnClickListener(v -> inviteToConversation(mConversation)); - this.binding.showUsers.setOnClickListener(v -> { - Intent intent = new Intent(this, MucUsersActivity.class); - intent.putExtra("uuid", mConversation.getUuid()); - startActivity(intent); - }); + this.binding.showUsers.setOnClickListener( + v -> { + Intent intent = new Intent(this, MucUsersActivity.class); + intent.putExtra("uuid", mConversation.getUuid()); + startActivity(intent); + }); } @Override public void onStart() { super.onStart(); - binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE); + binding.mediaWrapper.setVisibility( + Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE); } @Override @@ -261,23 +292,43 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.mAdvancedMode = !menuItem.isChecked(); menuItem.setChecked(this.mAdvancedMode); getPreferences().edit().putBoolean("advanced_muc_mode", mAdvancedMode).apply(); - final boolean online = mConversation != null && mConversation.getMucOptions().online(); - this.binding.mucInfoMore.setVisibility(this.mAdvancedMode && online ? View.VISIBLE : View.GONE); + final boolean online = + mConversation != null && mConversation.getMucOptions().online(); + this.binding.mucInfoMore.setVisibility( + this.mAdvancedMode && online ? View.VISIBLE : View.GONE); invalidateOptionsMenu(); updateView(); break; + case R.id.action_custom_notifications: + if (mConversation != null) { + configureCustomNotifications(mConversation); + } + break; } return super.onOptionsItemSelected(menuItem); } + private void configureCustomNotifications(final Conversation conversation) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R + || conversation.getMode() != Conversational.MODE_MULTI) { + return; + } + final var shortcut = + xmppConnectionService + .getShortcutService() + .getShortcutInfo(conversation.getMucOptions()); + configureCustomNotification(shortcut); + } + @Override - public boolean onContextItemSelected(MenuItem item) { + public boolean onContextItemSelected(@NonNull final MenuItem item) { final User user = mUserPreviewAdapter.getSelectedUser(); if (user == null) { Toast.makeText(this, R.string.unable_to_perform_this_action, Toast.LENGTH_SHORT).show(); return true; } - if (!MucDetailsContextMenuHelper.onContextItemSelected(item, mUserPreviewAdapter.getSelectedUser(), this)) { + if (!MucDetailsContextMenuHelper.onContextItemSelected( + item, mUserPreviewAdapter.getSelectedUser(), this)) { return super.onContextItemSelected(item); } return true; @@ -292,7 +343,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.editMucNameButton.setContentDescription(getString(R.string.cancel)); final String name = mucOptions.getName(); this.binding.mucEditTitle.setText(""); - final boolean owner = mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER); + final boolean owner = + mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER); if (owner || printableValue(name)) { this.binding.mucEditTitle.setVisibility(View.VISIBLE); if (name != null) { @@ -312,8 +364,14 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.mucEditSubject.requestFocus(); } } else { - String subject = this.binding.mucEditSubject.isEnabled() ? this.binding.mucEditSubject.getEditableText().toString().trim() : null; - String name = this.binding.mucEditTitle.isEnabled() ? this.binding.mucEditTitle.getEditableText().toString().trim() : null; + String subject = + this.binding.mucEditSubject.isEnabled() + ? this.binding.mucEditSubject.getEditableText().toString().trim() + : null; + String name = + this.binding.mucEditTitle.isEnabled() + ? this.binding.mucEditTitle.getEditableText().toString().trim() + : null; onMucInfoUpdated(subject, name); SoftKeyboardUtils.hideSoftKeyboard(this); hideEditor(); @@ -324,7 +382,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.mucEditor.setVisibility(View.GONE); this.binding.mucDisplay.setVisibility(View.VISIBLE); this.binding.editMucNameButton.setImageResource(R.drawable.ic_edit_24dp); - this.binding.editMucNameButton.setContentDescription(getString(R.string.edit_name_and_topic)); + this.binding.editMucNameButton.setContentDescription( + getString(R.string.edit_name_and_topic)); } private void onMucInfoUpdated(String subject, String name) { @@ -332,7 +391,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers if (mucOptions.canChangeSubject() && changed(mucOptions.getSubject(), subject)) { xmppConnectionService.pushSubjectToConference(mConversation, subject); } - if (mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER) && changed(mucOptions.getName(), name)) { + if (mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER) + && changed(mucOptions.getName(), name)) { Bundle options = new Bundle(); options.putString("muc#roomconfig_persistentroom", "1"); options.putString("muc#roomconfig_roomname", StringUtils.nullOnEmpty(name)); @@ -340,12 +400,13 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } } - @Override protected String getShareableUri(boolean http) { if (mConversation != null) { if (http) { - return "https://conversations.im/j/" + XmppUri.lameUrlEncode(mConversation.getJid().asBareJid().toEscapedString()); + return "https://conversations.im/j/" + + XmppUri.lameUrlEncode( + mConversation.getJid().asBareJid().toEscapedString()); } else { return "xmpp:" + mConversation.getJid().asBareJid() + "?join"; } @@ -364,7 +425,12 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers return true; } menuItemSaveBookmark.setVisible(mConversation.getBookmark() == null); - menuItemDestroyRoom.setVisible(mConversation.getMucOptions().getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER)); + menuItemDestroyRoom.setVisible( + mConversation + .getMucOptions() + .getSelf() + .getAffiliation() + .ranks(MucOptions.Affiliation.OWNER)); return true; } @@ -377,32 +443,40 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers final MenuItem destroy = menu.findItem(R.id.action_destroy_room); destroy.setTitle(groupChat ? R.string.destroy_room : R.string.destroy_channel); AccountUtils.showHideMenuItems(menu); + final MenuItem customNotifications = menu.findItem(R.id.action_custom_notifications); + customNotifications.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); return super.onCreateOptionsMenu(menu); } @Override - public void onMediaLoaded(List attachments) { - runOnUiThread(() -> { - int limit = GridManager.getCurrentColumnCount(binding.media); - mMediaAdapter.setAttachments(attachments.subList(0, Math.min(limit, attachments.size()))); - binding.mediaWrapper.setVisibility(attachments.size() > 0 ? View.VISIBLE : View.GONE); - }); - + public void onMediaLoaded(final List attachments) { + runOnUiThread( + () -> { + final int limit = GridManager.getCurrentColumnCount(binding.media); + mMediaAdapter.setAttachments( + attachments.subList(0, Math.min(limit, attachments.size()))); + binding.mediaWrapper.setVisibility( + attachments.isEmpty() ? View.GONE : View.VISIBLE); + }); } - protected void saveAsBookmark() { - xmppConnectionService.saveConversationAsBookmark(mConversation, mConversation.getMucOptions().getName()); + xmppConnectionService.saveConversationAsBookmark( + mConversation, mConversation.getMucOptions().getName()); } protected void destroyRoom() { final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous(); final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); builder.setTitle(groupChat ? R.string.destroy_room : R.string.destroy_channel); - builder.setMessage(groupChat ? R.string.destroy_room_dialog : R.string.destroy_channel_dialog); - builder.setPositiveButton(R.string.ok, (dialog, which) -> { - xmppConnectionService.destroyRoom(mConversation, ConferenceDetailsActivity.this); - }); + builder.setMessage( + groupChat ? R.string.destroy_room_dialog : R.string.destroy_channel_dialog); + builder.setPositiveButton( + R.string.ok, + (dialog, which) -> { + xmppConnectionService.destroyRoom( + mConversation, ConferenceDetailsActivity.this); + }); builder.setNegativeButton(R.string.cancel, null); final AlertDialog dialog = builder.create(); dialog.setCanceledOnTouchOutside(false); @@ -424,7 +498,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers if (Compatibility.hasStoragePermission(this)) { final int limit = GridManager.getCurrentColumnCount(this.binding.media); xmppConnectionService.getAttachments(this.mConversation, limit, this); - this.binding.showMedia.setOnClickListener((v) -> MediaBrowserActivity.launch(this, mConversation)); + this.binding.showMedia.setOnClickListener( + (v) -> MediaBrowserActivity.launch(this, mConversation)); } updateView(); } @@ -448,15 +523,24 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers final MucOptions mucOptions = mConversation.getMucOptions(); final User self = mucOptions.getSelf(); final String account = mConversation.getAccount().getJid().asBareJid().toEscapedString(); - setTitle(mucOptions.isPrivateAndNonAnonymous() ? R.string.action_muc_details : R.string.channel_details); - this.binding.editMucNameButton.setVisibility((self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) || mucOptions.canChangeSubject()) ? View.VISIBLE : View.GONE); + setTitle( + mucOptions.isPrivateAndNonAnonymous() + ? R.string.action_muc_details + : R.string.channel_details); + this.binding.editMucNameButton.setVisibility( + (self.getAffiliation().ranks(MucOptions.Affiliation.OWNER) + || mucOptions.canChangeSubject()) + ? View.VISIBLE + : View.GONE); this.binding.detailsAccount.setText(getString(R.string.using_account, account)); if (mConversation.isPrivateAndNonAnonymous()) { - this.binding.jid.setText(getString(R.string.hosted_on, mConversation.getJid().getDomain())); + this.binding.jid.setText( + getString(R.string.hosted_on, mConversation.getJid().getDomain())); } else { this.binding.jid.setText(mConversation.getJid().asBareJid().toEscapedString()); } - AvatarWorkerTask.loadAvatar(mConversation, binding.yourPhoto, R.dimen.avatar_on_details_screen_size); + AvatarWorkerTask.loadAvatar( + mConversation, binding.yourPhoto, R.dimen.avatar_on_details_screen_size); String roomName = mucOptions.getName(); String subject = mucOptions.getSubject(); final boolean hasTitle; @@ -477,7 +561,12 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers StylingHelper.format(spannable, this.binding.mucSubject.getCurrentTextColor()); MyLinkify.addLinks(spannable, false); this.binding.mucSubject.setText(spannable); - this.binding.mucSubject.setTextAppearance( subject.length() > (hasTitle ? 128 : 196) ? com.google.android.material.R.style.TextAppearance_Material3_BodyMedium : com.google.android.material.R.style.TextAppearance_Material3_BodyLarge); + this.binding.mucSubject.setTextAppearance( + subject.length() > (hasTitle ? 128 : 196) + ? com.google.android.material.R.style + .TextAppearance_Material3_BodyMedium + : com.google.android.material.R.style + .TextAppearance_Material3_BodyLarge); this.binding.mucSubject.setAutoLinkMask(0); this.binding.mucSubject.setVisibility(View.VISIBLE); this.binding.mucSubject.setMovementMethod(LinkMovementMethod.getInstance()); @@ -495,7 +584,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers this.binding.mucConferenceType.setText(MucConfiguration.describe(this, mucOptions)); } else if (!mucOptions.isPrivateAndNonAnonymous() && mucOptions.nonanonymous()) { this.binding.mucSettings.setVisibility(View.VISIBLE); - this.binding.mucConferenceType.setText(R.string.group_chat_will_make_your_jabber_id_public); + this.binding.mucConferenceType.setText( + R.string.group_chat_will_make_your_jabber_id_public); } else { this.binding.mucSettings.setVisibility(View.GONE); } @@ -518,50 +608,64 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers final long mutedTill = mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0); if (mutedTill == Long.MAX_VALUE) { this.binding.notificationStatusText.setText(R.string.notify_never); - this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_off_24dp); + this.binding.notificationStatusButton.setImageResource( + R.drawable.ic_notifications_off_24dp); } else if (System.currentTimeMillis() < mutedTill) { this.binding.notificationStatusText.setText(R.string.notify_paused); - this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_paused_24dp); + this.binding.notificationStatusButton.setImageResource( + R.drawable.ic_notifications_paused_24dp); } else if (mConversation.alwaysNotify()) { this.binding.notificationStatusText.setText(R.string.notify_on_all_messages); - this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_24dp); + this.binding.notificationStatusButton.setImageResource( + R.drawable.ic_notifications_24dp); } else { this.binding.notificationStatusText.setText(R.string.notify_only_when_highlighted); - this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_none_24dp); + this.binding.notificationStatusButton.setImageResource( + R.drawable.ic_notifications_none_24dp); } final List users = mucOptions.getUsers(); - Collections.sort(users, (a, b) -> { - if (b.getAffiliation().outranks(a.getAffiliation())) { - return 1; - } else if (a.getAffiliation().outranks(b.getAffiliation())) { - return -1; - } else { - if (a.getAvatar() != null && b.getAvatar() == null) { - return -1; - } else if (a.getAvatar() == null && b.getAvatar() != null) { - return 1; - } else { - return a.getComparableName().compareToIgnoreCase(b.getComparableName()); - } - } - }); - this.mUserPreviewAdapter.submitList(MucOptions.sub(users, GridManager.getCurrentColumnCount(binding.users))); + Collections.sort( + users, + (a, b) -> { + if (b.getAffiliation().outranks(a.getAffiliation())) { + return 1; + } else if (a.getAffiliation().outranks(b.getAffiliation())) { + return -1; + } else { + if (a.getAvatar() != null && b.getAvatar() == null) { + return -1; + } else if (a.getAvatar() == null && b.getAvatar() != null) { + return 1; + } else { + return a.getComparableName().compareToIgnoreCase(b.getComparableName()); + } + } + }); + this.mUserPreviewAdapter.submitList( + MucOptions.sub(users, GridManager.getCurrentColumnCount(binding.users))); this.binding.invite.setVisibility(mucOptions.canInvite() ? View.VISIBLE : View.GONE); this.binding.showUsers.setVisibility(users.size() > 0 ? View.VISIBLE : View.GONE); - this.binding.showUsers.setText(getResources().getQuantityString(R.plurals.view_users, users.size(), users.size())); - this.binding.usersWrapper.setVisibility(users.size() > 0 || mucOptions.canInvite() ? View.VISIBLE : View.GONE); + this.binding.showUsers.setText( + getResources().getQuantityString(R.plurals.view_users, users.size(), users.size())); + this.binding.usersWrapper.setVisibility( + users.size() > 0 || mucOptions.canInvite() ? View.VISIBLE : View.GONE); if (users.size() == 0) { - this.binding.noUsersHints.setText(mucOptions.isPrivateAndNonAnonymous() ? R.string.no_users_hint_group_chat : R.string.no_users_hint_channel); + this.binding.noUsersHints.setText( + mucOptions.isPrivateAndNonAnonymous() + ? R.string.no_users_hint_group_chat + : R.string.no_users_hint_channel); this.binding.noUsersHints.setVisibility(View.VISIBLE); } else { this.binding.noUsersHints.setVisibility(View.GONE); } - } public static String getStatus(Context context, User user, final boolean advanced) { if (advanced) { - return String.format("%s (%s)", context.getString(user.getAffiliation().getResId()), context.getString(user.getRole().getResId())); + return String.format( + "%s (%s)", + context.getString(user.getAffiliation().getResId()), + context.getString(user.getRole().getResId())); } else { return context.getString(user.getAffiliation().getResId()); } @@ -571,7 +675,6 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers return getStatus(this, user, mAdvancedMode); } - @Override public void onAffiliationChangedSuccessful(Jid jid) { refreshUi(); @@ -590,7 +693,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers @Override public void onRoomDestroyFailed() { final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous(); - displayToast(getString(groupChat ? R.string.could_not_destroy_room : R.string.could_not_destroy_channel)); + displayToast( + getString( + groupChat + ? R.string.could_not_destroy_room + : R.string.could_not_destroy_channel)); } @Override @@ -604,23 +711,20 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } private void displayToast(final String msg) { - runOnUiThread(() -> { - if (isFinishing()) { - return; - } - ToastCompat.makeText(this, msg, Toast.LENGTH_SHORT).show(); - }); + runOnUiThread( + () -> { + if (isFinishing()) { + return; + } + ToastCompat.makeText(this, msg, Toast.LENGTH_SHORT).show(); + }); } @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } + public void onTextChanged(CharSequence s, int start, int before, int count) {} @Override public void afterTextChanged(Editable s) { @@ -629,8 +733,14 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } final MucOptions mucOptions = mConversation.getMucOptions(); if (this.binding.mucEditor.getVisibility() == View.VISIBLE) { - boolean subjectChanged = changed(binding.mucEditSubject.getEditableText().toString(), mucOptions.getSubject()); - boolean nameChanged = changed(binding.mucEditTitle.getEditableText().toString(), mucOptions.getName()); + boolean subjectChanged = + changed( + binding.mucEditSubject.getEditableText().toString(), + mucOptions.getSubject()); + boolean nameChanged = + changed( + binding.mucEditTitle.getEditableText().toString(), + mucOptions.getName()); if (subjectChanged || nameChanged) { this.binding.editMucNameButton.setImageResource(R.drawable.ic_save_24dp); this.binding.editMucNameButton.setContentDescription(getString(R.string.save)); @@ -640,5 +750,4 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } } } - } diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 5eb368b7e8c38e32ab10463610faabe0a2894ddd..69e78124f9c881d9bb2725a0934c41bfcedcc4c2 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -26,23 +26,14 @@ import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.TextView; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.core.view.ViewCompat; import androidx.databinding.DataBindingUtil; - import com.google.android.material.color.MaterialColors; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Ints; - -import org.openintents.openpgp.util.OpenPgpUtils; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -78,48 +69,72 @@ import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.XmppConnection; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.openintents.openpgp.util.OpenPgpUtils; -public class ContactDetailsActivity extends OmemoActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated, OnMediaLoaded { +public class ContactDetailsActivity extends OmemoActivity + implements OnAccountUpdate, + OnRosterUpdate, + OnUpdateBlocklist, + OnKeyStatusUpdated, + OnMediaLoaded { public static final String ACTION_VIEW_CONTACT = "view_contact"; private final int REQUEST_SYNC_CONTACTS = 0x28cf; ActivityContactDetailsBinding binding; private MediaAdapter mMediaAdapter; private Contact contact; - private final DialogInterface.OnClickListener removeFromRoster = new DialogInterface.OnClickListener() { + private final DialogInterface.OnClickListener removeFromRoster = + new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - xmppConnectionService.deleteContactOnServer(contact); - } - }; - private final OnCheckedChangeListener mOnSendCheckedChange = new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { - xmppConnectionService.stopPresenceUpdatesTo(contact); - } else { - contact.setOption(Contact.Options.PREEMPTIVE_GRANT); + @Override + public void onClick(DialogInterface dialog, int which) { + xmppConnectionService.deleteContactOnServer(contact); } - } else { - contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); - xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator().stopPresenceUpdatesTo(contact)); - } - } - }; - private final OnCheckedChangeListener mOnReceiveCheckedChange = new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator().requestPresenceUpdatesFrom(contact)); - } else { - xmppConnectionService.sendPresencePacket(contact.getAccount(), xmppConnectionService.getPresenceGenerator().stopPresenceUpdatesFrom(contact)); - } - } - }; + }; + private final OnCheckedChangeListener mOnSendCheckedChange = + new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { + xmppConnectionService.stopPresenceUpdatesTo(contact); + } else { + contact.setOption(Contact.Options.PREEMPTIVE_GRANT); + } + } else { + contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); + xmppConnectionService.sendPresencePacket( + contact.getAccount(), + xmppConnectionService + .getPresenceGenerator() + .stopPresenceUpdatesTo(contact)); + } + } + }; + private final OnCheckedChangeListener mOnReceiveCheckedChange = + new OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + xmppConnectionService.sendPresencePacket( + contact.getAccount(), + xmppConnectionService + .getPresenceGenerator() + .requestPresenceUpdatesFrom(contact)); + } else { + xmppConnectionService.sendPresencePacket( + contact.getAccount(), + xmppConnectionService + .getPresenceGenerator() + .stopPresenceUpdatesFrom(contact)); + } + } + }; private Jid accountJid; private Jid contactJid; private boolean showDynamicTags = false; @@ -130,14 +145,18 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp private void checkContactPermissionAndShowAddDialog() { if (hasContactsPermission()) { showAddToPhoneBookDialog(); - } else if (QuickConversationsService.isContactListIntegration(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS); + } else if (QuickConversationsService.isContactListIntegration(this) + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions( + new String[] {Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS); } } private boolean hasContactsPermission() { - if (QuickConversationsService.isContactListIntegration(this) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - return checkSelfPermission(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED; + if (QuickConversationsService.isContactListIntegration(this) + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return checkSelfPermission(Manifest.permission.READ_CONTACTS) + == PackageManager.PERMISSION_GRANTED; } else { return true; } @@ -145,9 +164,10 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp private void showAddToPhoneBookDialog() { final Jid jid = contact.getJid(); - final boolean quicksyContact = AbstractQuickConversationsService.isQuicksy() - && Config.QUICKSY_DOMAIN.equals(jid.getDomain()) - && jid.getLocal() != null; + final boolean quicksyContact = + AbstractQuickConversationsService.isQuicksy() + && Config.QUICKSY_DOMAIN.equals(jid.getDomain()) + && jid.getLocal() != null; final String value; if (quicksyContact) { value = PhoneNumberUtilWrapper.toFormattedPhoneNumber(this, jid); @@ -158,24 +178,33 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp builder.setTitle(getString(R.string.action_add_phone_book)); builder.setMessage(getString(R.string.add_phone_book_text, value)); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.add), (dialog, which) -> { - final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); - intent.setType(Contacts.CONTENT_ITEM_TYPE); - if (quicksyContact) { - intent.putExtra(Intents.Insert.PHONE, value); - } else { - intent.putExtra(Intents.Insert.IM_HANDLE, value); - intent.putExtra(Intents.Insert.IM_PROTOCOL, CommonDataKinds.Im.PROTOCOL_JABBER); - //TODO for modern use we want PROTOCOL_CUSTOM and an extra field with a value of 'XMPP' - // however we don’t have such a field and thus have to use the legacy PROTOCOL_JABBER - } - intent.putExtra("finishActivityOnSaveCompleted", true); - try { - startActivityForResult(intent, 0); - } catch (ActivityNotFoundException e) { - Toast.makeText(ContactDetailsActivity.this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show(); - } - }); + builder.setPositiveButton( + getString(R.string.add), + (dialog, which) -> { + final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); + intent.setType(Contacts.CONTENT_ITEM_TYPE); + if (quicksyContact) { + intent.putExtra(Intents.Insert.PHONE, value); + } else { + intent.putExtra(Intents.Insert.IM_HANDLE, value); + intent.putExtra( + Intents.Insert.IM_PROTOCOL, CommonDataKinds.Im.PROTOCOL_JABBER); + // TODO for modern use we want PROTOCOL_CUSTOM and an extra field with a + // value of 'XMPP' + // however we don’t have such a field and thus have to use the legacy + // PROTOCOL_JABBER + } + intent.putExtra("finishActivityOnSaveCompleted", true); + try { + startActivityForResult(intent, 0); + } catch (ActivityNotFoundException e) { + Toast.makeText( + ContactDetailsActivity.this, + R.string.no_application_found_to_view_contact, + Toast.LENGTH_SHORT) + .show(); + } + }); builder.create().show(); } @@ -203,7 +232,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp @Override protected String getShareableUri(boolean http) { if (http) { - return "https://conversations.im/i/" + XmppUri.lameUrlEncode(contact.getJid().asBareJid().toEscapedString()); + return "https://conversations.im/i/" + + XmppUri.lameUrlEncode(contact.getJid().asBareJid().toEscapedString()); } else { return "xmpp:" + contact.getJid().asBareJid().toEscapedString(); } @@ -212,7 +242,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - showInactiveOmemo = savedInstanceState != null && savedInstanceState.getBoolean("show_inactive_omemo", false); + showInactiveOmemo = + savedInstanceState != null + && savedInstanceState.getBoolean("show_inactive_omemo", false); if (getIntent().getAction().equals(ACTION_VIEW_CONTACT)) { try { this.accountJid = Jid.ofEscaped(getIntent().getExtras().getString(EXTRA_ACCOUNT)); @@ -229,10 +261,11 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp setSupportActionBar(binding.toolbar); configureActionBar(getSupportActionBar()); - binding.showInactiveDevices.setOnClickListener(v -> { - showInactiveOmemo = !showInactiveOmemo; - populateView(); - }); + binding.showInactiveDevices.setOnClickListener( + v -> { + showInactiveOmemo = !showInactiveOmemo; + populateView(); + }); binding.addContactButton.setOnClickListener(v -> showAddToRosterDialog(contact)); mMediaAdapter = new MediaAdapter(this, R.dimen.media_size); @@ -252,12 +285,14 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); this.showDynamicTags = preferences.getBoolean(AppSettings.SHOW_DYNAMIC_TAGS, false); this.showLastSeen = preferences.getBoolean("last_activity", false); - binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE); + binding.mediaWrapper.setVisibility( + Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE); mMediaAdapter.setAttachments(Collections.emptyList()); } @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { // TODO check for Camera / Scan permission super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (grantResults.length > 0) @@ -289,19 +324,29 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); builder.setNegativeButton(getString(R.string.cancel), null); builder.setTitle(getString(R.string.action_delete_contact)) - .setMessage(JidDialog.style(this, R.string.remove_contact_text, contact.getJid().toEscapedString())) - .setPositiveButton(getString(R.string.delete), - removeFromRoster).create().show(); + .setMessage( + JidDialog.style( + this, + R.string.remove_contact_text, + contact.getJid().toEscapedString())) + .setPositiveButton(getString(R.string.delete), removeFromRoster) + .create() + .show(); break; case R.id.action_edit_contact: - Uri systemAccount = contact.getSystemAccount(); + final Uri systemAccount = contact.getSystemAccount(); if (systemAccount == null) { - quickEdit(contact.getServerName(), R.string.contact_name, value -> { - contact.setServerName(value); - ContactDetailsActivity.this.xmppConnectionService.pushContactToServer(contact); - populateView(); - return null; - }, true); + quickEdit( + contact.getServerName(), + R.string.contact_name, + value -> { + contact.setServerName(value); + ContactDetailsActivity.this.xmppConnectionService + .pushContactToServer(contact); + populateView(); + return null; + }, + true); } else { Intent intent = new Intent(Intent.ACTION_EDIT); intent.setDataAndType(systemAccount, Contacts.CONTENT_ITEM_TYPE); @@ -309,29 +354,42 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp try { startActivity(intent); } catch (ActivityNotFoundException e) { - Toast.makeText(ContactDetailsActivity.this, R.string.no_application_found_to_view_contact, Toast.LENGTH_SHORT).show(); + Toast.makeText( + ContactDetailsActivity.this, + R.string.no_application_found_to_view_contact, + Toast.LENGTH_SHORT) + .show(); } - } break; - case R.id.action_block: + case R.id.action_block, R.id.action_unblock: BlockContactDialog.show(this, contact); break; - case R.id.action_unblock: - BlockContactDialog.show(this, contact); + case R.id.action_custom_notifications: + configureCustomNotifications(contact); break; } return super.onOptionsItemSelected(menuItem); } + private void configureCustomNotifications(final Contact contact) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + return; + } + final var shortcut = xmppConnectionService.getShortcutService().getShortcutInfo(contact); + configureCustomNotification(shortcut); + } + @Override public boolean onCreateOptionsMenu(final Menu menu) { getMenuInflater().inflate(R.menu.contact_details, menu); AccountUtils.showHideMenuItems(menu); - MenuItem block = menu.findItem(R.id.action_block); - MenuItem unblock = menu.findItem(R.id.action_unblock); - MenuItem edit = menu.findItem(R.id.action_edit_contact); - MenuItem delete = menu.findItem(R.id.action_delete_contact); + final MenuItem block = menu.findItem(R.id.action_block); + final MenuItem unblock = menu.findItem(R.id.action_unblock); + final MenuItem edit = menu.findItem(R.id.action_edit_contact); + final MenuItem delete = menu.findItem(R.id.action_delete_contact); + final MenuItem customNotifications = menu.findItem(R.id.action_custom_notifications); + customNotifications.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); if (contact == null) { return true; } @@ -374,7 +432,11 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp binding.statusMessage.setVisibility(View.VISIBLE); final Spannable span = new SpannableString(message); if (Emoticons.isOnlyEmoji(message)) { - span.setSpan(new RelativeSizeSpan(2.0f), 0, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + span.setSpan( + new RelativeSizeSpan(2.0f), + 0, + message.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } binding.statusMessage.setText(span); } else { @@ -398,14 +460,16 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp binding.detailsSendPresence.setText(R.string.send_presence_updates); } else { binding.detailsSendPresence.setText(R.string.preemptively_grant); - binding.detailsSendPresence.setChecked(contact.getOption(Contact.Options.PREEMPTIVE_GRANT)); + binding.detailsSendPresence.setChecked( + contact.getOption(Contact.Options.PREEMPTIVE_GRANT)); } if (contact.getOption(Contact.Options.TO)) { binding.detailsReceivePresence.setText(R.string.receive_presence_updates); binding.detailsReceivePresence.setChecked(true); } else { binding.detailsReceivePresence.setText(R.string.ask_for_presence_updates); - binding.detailsReceivePresence.setChecked(contact.getOption(Contact.Options.ASKING)); + binding.detailsReceivePresence.setChecked( + contact.getOption(Contact.Options.ASKING)); } if (contact.getAccount().isOnlineAndConnected()) { binding.detailsReceivePresence.setEnabled(true); @@ -431,7 +495,11 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp && contact.getLastseen() > 0 && contact.getPresences().allOrNonSupport(Namespace.IDLE)) { binding.detailsLastseen.setVisibility(View.VISIBLE); - binding.detailsLastseen.setText(UIHelper.lastseen(getApplicationContext(), contact.isActive(), contact.getLastseen())); + binding.detailsLastseen.setText( + UIHelper.lastseen( + getApplicationContext(), + contact.isActive(), + contact.getLastseen())); } else { binding.detailsLastseen.setVisibility(View.GONE); } @@ -440,7 +508,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this, contact.getJid())); final String account = contact.getAccount().getJid().asBareJid().toEscapedString(); binding.detailsAccount.setText(getString(R.string.using_account, account)); - AvatarWorkerTask.loadAvatar(contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size); + AvatarWorkerTask.loadAvatar( + contact, binding.detailsContactBadge, R.dimen.avatar_on_details_screen_size); binding.detailsContactBadge.setOnClickListener(this::onBadgeClick); binding.detailsContactKeys.removeAllViews(); @@ -448,7 +517,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final LayoutInflater inflater = getLayoutInflater(); final AxolotlService axolotlService = contact.getAccount().getAxolotlService(); if (Config.supportOmemo() && axolotlService != null) { - final Collection sessions = axolotlService.findSessionsForContact(contact); + final Collection sessions = + axolotlService.findSessionsForContact(contact); boolean anyActive = false; for (XmppAxolotlSession session : sessions) { anyActive = session.getTrust().isActive(); @@ -478,9 +548,13 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp showUnverifiedWarning = true; } } - binding.unverifiedWarning.setVisibility(showUnverifiedWarning ? View.VISIBLE : View.GONE); + binding.unverifiedWarning.setVisibility( + showUnverifiedWarning ? View.VISIBLE : View.GONE); if (showsInactive || skippedInactive) { - binding.showInactiveDevices.setText(showsInactive ? R.string.hide_inactive_devices : R.string.show_inactive_devices); + binding.showInactiveDevices.setText( + showsInactive + ? R.string.hide_inactive_devices + : R.string.show_inactive_devices); binding.showInactiveDevices.setVisibility(View.VISIBLE); } else { binding.showInactiveDevices.setVisibility(View.GONE); @@ -489,7 +563,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp binding.showInactiveDevices.setVisibility(View.GONE); } final boolean isCameraFeatureAvailable = isCameraFeatureAvailable(); - binding.scanButton.setVisibility(hasKeys && isCameraFeatureAvailable ? View.VISIBLE : View.GONE); + binding.scanButton.setVisibility( + hasKeys && isCameraFeatureAvailable ? View.VISIBLE : View.GONE); if (hasKeys) { binding.scanButton.setOnClickListener((v) -> ScanActivity.scan(this)); } @@ -500,7 +575,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp TextView keyType = view.findViewById(R.id.key_type); keyType.setText(R.string.openpgp_key_id); if ("pgp".equals(messageFingerprint)) { - keyType.setTextColor(MaterialColors.getColor(keyType, com.google.android.material.R.attr.colorPrimaryVariant)); + keyType.setTextColor( + MaterialColors.getColor( + keyType, com.google.android.material.R.attr.colorPrimaryVariant)); } key.setText(OpenPgpUtils.convertKeyIdToHex(contact.getPgpKeyId())); final OnClickListener openKey = v -> launchOpenKeyChain(contact.getPgpKeyId()); @@ -512,7 +589,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp binding.keysWrapper.setVisibility(hasKeys ? View.VISIBLE : View.GONE); final List tagList = contact.getTags(this); - final boolean hasMetaTags = contact.isBlocked() || contact.getShownStatus() != Presence.Status.OFFLINE; + final boolean hasMetaTags = + contact.isBlocked() || contact.getShownStatus() != Presence.Status.OFFLINE; if ((tagList.isEmpty() && !hasMetaTags) || !this.showDynamicTags) { binding.tags.setVisibility(View.GONE); } else { @@ -521,9 +599,13 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final ImmutableList.Builder viewIdBuilder = new ImmutableList.Builder<>(); for (final ListItem.Tag tag : tagList) { final String name = tag.getName(); - final TextView tv = (TextView) inflater.inflate(R.layout.item_tag, binding.tags, false); + final TextView tv = + (TextView) inflater.inflate(R.layout.item_tag, binding.tags, false); tv.setText(name); - tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(this,XEP0392Helper.rgbFromNick(name)))); + tv.setBackgroundTintList( + ColorStateList.valueOf( + MaterialColors.harmonizeWithPrimary( + this, XEP0392Helper.rgbFromNick(name)))); final int id = ViewCompat.generateViewId(); tv.setId(id); viewIdBuilder.add(id); @@ -531,11 +613,14 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp } if (contact.isBlocked()) { final TextView tv = - (TextView) - inflater.inflate( - R.layout.item_tag, binding.tags, false); + (TextView) inflater.inflate(R.layout.item_tag, binding.tags, false); tv.setText(R.string.blocked); - tv.setBackgroundTintList(ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(tv.getContext(), ContextCompat.getColor(tv.getContext(),R.color.gray_800)))); + tv.setBackgroundTintList( + ColorStateList.valueOf( + MaterialColors.harmonizeWithPrimary( + tv.getContext(), + ContextCompat.getColor( + tv.getContext(), R.color.gray_800)))); final int id = ViewCompat.generateViewId(); tv.setId(id); viewIdBuilder.add(id); @@ -544,9 +629,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp final Presence.Status status = contact.getShownStatus(); if (status != Presence.Status.OFFLINE) { final TextView tv = - (TextView) - inflater.inflate( - R.layout.item_tag, binding.tags, false); + (TextView) inflater.inflate(R.layout.item_tag, binding.tags, false); UIHelper.setStatus(tv, status); final int id = ViewCompat.generateViewId(); tv.setId(id); @@ -599,8 +682,10 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp if (Compatibility.hasStoragePermission(this)) { final int limit = GridManager.getCurrentColumnCount(this.binding.media); - xmppConnectionService.getAttachments(account, contact.getJid().asBareJid(), limit, this); - this.binding.showMedia.setOnClickListener((v) -> MediaBrowserActivity.launch(this, contact)); + xmppConnectionService.getAttachments( + account, contact.getJid().asBareJid(), limit, this); + this.binding.showMedia.setOnClickListener( + (v) -> MediaBrowserActivity.launch(this, contact)); } populateView(); } @@ -613,7 +698,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp @Override protected void processFingerprintVerification(XmppUri uri) { - if (contact != null && contact.getJid().asBareJid().equals(uri.getJid()) && uri.hasFingerprints()) { + if (contact != null + && contact.getJid().asBareJid().equals(uri.getJid()) + && uri.hasFingerprints()) { if (xmppConnectionService.verifyFingerprints(contact, uri.getFingerprints())) { Toast.makeText(this, R.string.verified_fingerprints, Toast.LENGTH_SHORT).show(); } @@ -624,11 +711,13 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp @Override public void onMediaLoaded(List attachments) { - runOnUiThread(() -> { - int limit = GridManager.getCurrentColumnCount(binding.media); - mMediaAdapter.setAttachments(attachments.subList(0, Math.min(limit, attachments.size()))); - binding.mediaWrapper.setVisibility(attachments.size() > 0 ? View.VISIBLE : View.GONE); - }); - + runOnUiThread( + () -> { + int limit = GridManager.getCurrentColumnCount(binding.media); + mMediaAdapter.setAttachments( + attachments.subList(0, Math.min(limit, attachments.size()))); + binding.mediaWrapper.setVisibility( + attachments.size() > 0 ? View.VISIBLE : View.GONE); + }); } } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 0798994f6adc1d49be6a869f05a9da9d345fac1a..fa304e810fb2f4cff824448cc0266ce4208d7292 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -2,6 +2,7 @@ package eu.siacs.conversations.ui; import android.Manifest; import android.annotation.SuppressLint; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.ClipData; @@ -15,7 +16,6 @@ import android.content.IntentSender.SendIntentException; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Point; @@ -31,6 +31,7 @@ import android.os.IBinder; import android.os.PowerManager; import android.os.SystemClock; import android.preference.PreferenceManager; +import android.provider.Settings; import android.text.Html; import android.text.InputType; import android.util.DisplayMetrics; @@ -42,19 +43,19 @@ import android.widget.Button; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.Toast; - import androidx.annotation.BoolRes; import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; import androidx.annotation.StringRes; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDelegate; +import androidx.core.content.pm.ShortcutInfoCompat; +import androidx.core.content.pm.ShortcutManagerCompat; import androidx.databinding.DataBindingUtil; - import com.google.android.material.color.MaterialColors; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; - import eu.siacs.conversations.AppSettings; import eu.siacs.conversations.BuildConfig; import eu.siacs.conversations.Config; @@ -70,6 +71,7 @@ import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.entities.Reaction; import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.BarcodeProvider; +import eu.siacs.conversations.services.NotificationService; import eu.siacs.conversations.services.QuickConversationsService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; @@ -79,16 +81,13 @@ import eu.siacs.conversations.ui.util.SettingsUtils; import eu.siacs.conversations.ui.util.SoftKeyboardUtils; import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.Compatibility; -import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.SignupUtils; import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; - import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.RejectedExecutionException; @@ -112,50 +111,58 @@ public abstract class XmppActivity extends ActionBarActivity { protected boolean mUsingEnterKey = false; protected boolean mUseTor = false; protected Toast mToast; - public Runnable onOpenPGPKeyPublished = () -> Toast.makeText(XmppActivity.this, R.string.openpgp_has_been_published, Toast.LENGTH_SHORT).show(); + public Runnable onOpenPGPKeyPublished = + () -> + Toast.makeText( + XmppActivity.this, + R.string.openpgp_has_been_published, + Toast.LENGTH_SHORT) + .show(); protected ConferenceInvite mPendingConferenceInvite = null; - protected ServiceConnection mConnection = new ServiceConnection() { + protected ServiceConnection mConnection = + new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - XmppConnectionBinder binder = (XmppConnectionBinder) service; - xmppConnectionService = binder.getService(); - xmppConnectionServiceBound = true; - registerListeners(); - onBackendConnected(); - } + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + XmppConnectionBinder binder = (XmppConnectionBinder) service; + xmppConnectionService = binder.getService(); + xmppConnectionServiceBound = true; + registerListeners(); + onBackendConnected(); + } - @Override - public void onServiceDisconnected(ComponentName arg0) { - xmppConnectionServiceBound = false; - } - }; + @Override + public void onServiceDisconnected(ComponentName arg0) { + xmppConnectionServiceBound = false; + } + }; private DisplayMetrics metrics; private long mLastUiRefresh = 0; private final Handler mRefreshUiHandler = new Handler(); - private final Runnable mRefreshUiRunnable = () -> { - mLastUiRefresh = SystemClock.elapsedRealtime(); - refreshUiReal(); - }; - private final UiCallback adhocCallback = new UiCallback() { - @Override - public void success(final Conversation conversation) { - runOnUiThread(() -> { - switchToConversation(conversation); - hideToast(); - }); - } - - @Override - public void error(final int errorCode, Conversation object) { - runOnUiThread(() -> replaceToast(getString(errorCode))); - } + private final Runnable mRefreshUiRunnable = + () -> { + mLastUiRefresh = SystemClock.elapsedRealtime(); + refreshUiReal(); + }; + private final UiCallback adhocCallback = + new UiCallback() { + @Override + public void success(final Conversation conversation) { + runOnUiThread( + () -> { + switchToConversation(conversation); + hideToast(); + }); + } - @Override - public void userInputRequired(PendingIntent pi, Conversation object) { + @Override + public void error(final int errorCode, Conversation object) { + runOnUiThread(() -> replaceToast(getString(errorCode))); + } - } - }; + @Override + public void userInputRequired(PendingIntent pi, Conversation object) {} + }; public static boolean cancelPotentialWork(Message message, ImageView imageView) { final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); @@ -212,7 +219,7 @@ public abstract class XmppActivity extends ActionBarActivity { } } - abstract protected void refreshUiReal(); + protected abstract void refreshUiReal(); @Override public void onStart() { @@ -248,6 +255,41 @@ public abstract class XmppActivity extends ActionBarActivity { } } + @RequiresApi(api = Build.VERSION_CODES.R) + protected void configureCustomNotification(final ShortcutInfoCompat shortcut) { + final var notificationManager = getSystemService(NotificationManager.class); + final var channel = + notificationManager.getNotificationChannel( + NotificationService.MESSAGES_NOTIFICATION_CHANNEL, shortcut.getId()); + if (channel != null && channel.getConversationId() != null) { + ShortcutManagerCompat.pushDynamicShortcut(this, shortcut); + openNotificationSettings(shortcut); + } else { + new MaterialAlertDialogBuilder(this) + .setTitle(R.string.custom_notifications) + .setMessage(R.string.custom_notifications_enable) + .setPositiveButton( + R.string.continue_btn, + (d, w) -> { + NotificationService.createConversationChannel(this, shortcut); + ShortcutManagerCompat.pushDynamicShortcut(this, shortcut); + openNotificationSettings(shortcut); + }) + .setNegativeButton(R.string.cancel, null) + .create() + .show(); + } + } + + @RequiresApi(api = Build.VERSION_CODES.R) + protected void openNotificationSettings(final ShortcutInfoCompat shortcut) { + final var intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); + intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); + intent.putExtra( + Settings.EXTRA_CHANNEL_ID, NotificationService.MESSAGES_NOTIFICATION_CHANNEL); + intent.putExtra(Settings.EXTRA_CONVERSATION_ID, shortcut.getId()); + startActivity(intent); + } public boolean hasPgp() { return xmppConnectionService.getPgpEngine() != null; @@ -257,16 +299,20 @@ public abstract class XmppActivity extends ActionBarActivity { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); builder.setTitle(getString(R.string.openkeychain_required)); builder.setIconAttribute(android.R.attr.alertDialogIcon); - builder.setMessage(Html.fromHtml(getString(R.string.openkeychain_required_long, getString(R.string.app_name)))); + builder.setMessage( + Html.fromHtml( + getString( + R.string.openkeychain_required_long, + getString(R.string.app_name)))); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setNeutralButton(getString(R.string.restart), + builder.setNeutralButton( + getString(R.string.restart), (dialog, which) -> { if (xmppConnectionServiceBound) { unbindService(mConnection); xmppConnectionServiceBound = false; } - stopService(new Intent(XmppActivity.this, - XmppConnectionService.class)); + stopService(new Intent(XmppActivity.this, XmppConnectionService.class)); finish(); }); builder.setPositiveButton( @@ -344,58 +390,89 @@ public abstract class XmppActivity extends ActionBarActivity { protected void deleteAccount(final Account account, final Runnable postDelete) { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); final View dialogView = getLayoutInflater().inflate(R.layout.dialog_delete_account, null); - final CheckBox deleteFromServer = - dialogView.findViewById(R.id.delete_from_server); + final CheckBox deleteFromServer = dialogView.findViewById(R.id.delete_from_server); builder.setView(dialogView); builder.setTitle(R.string.mgmt_account_delete); - builder.setPositiveButton(getString(R.string.delete),null); + builder.setPositiveButton(getString(R.string.delete), null); builder.setNegativeButton(getString(R.string.cancel), null); final AlertDialog dialog = builder.create(); - dialog.setOnShowListener(dialogInterface->{ - final Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE); - button.setOnClickListener(v -> { - final boolean unregister = deleteFromServer.isChecked(); - if (unregister) { - if (account.isOnlineAndConnected()) { - deleteFromServer.setEnabled(false); - button.setText(R.string.please_wait); - button.setEnabled(false); - xmppConnectionService.unregisterAccount(account, result -> { - runOnUiThread(()->{ - if (result) { - dialog.dismiss(); - if (postDelete != null) { - postDelete.run(); + dialog.setOnShowListener( + dialogInterface -> { + final Button button = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + button.setOnClickListener( + v -> { + final boolean unregister = deleteFromServer.isChecked(); + if (unregister) { + if (account.isOnlineAndConnected()) { + deleteFromServer.setEnabled(false); + button.setText(R.string.please_wait); + button.setEnabled(false); + xmppConnectionService.unregisterAccount( + account, + result -> { + runOnUiThread( + () -> { + if (result) { + dialog.dismiss(); + if (postDelete != null) { + postDelete.run(); + } + if (xmppConnectionService + .getAccounts() + .size() + == 0 + && Config + .MAGIC_CREATE_DOMAIN + != null) { + final Intent intent = + SignupUtils + .getSignUpIntent( + this); + intent.setFlags( + Intent + .FLAG_ACTIVITY_NEW_TASK + | Intent + .FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + } + } else { + deleteFromServer.setEnabled( + true); + button.setText(R.string.delete); + button.setEnabled(true); + Toast.makeText( + this, + R.string + .could_not_delete_account_from_server, + Toast + .LENGTH_LONG) + .show(); + } + }); + }); + } else { + Toast.makeText( + this, + R.string.not_connected_try_again, + Toast.LENGTH_LONG) + .show(); } - if (xmppConnectionService.getAccounts().size() == 0 && Config.MAGIC_CREATE_DOMAIN != null) { + } else { + xmppConnectionService.deleteAccount(account); + dialog.dismiss(); + if (xmppConnectionService.getAccounts().size() == 0 + && Config.MAGIC_CREATE_DOMAIN != null) { final Intent intent = SignupUtils.getSignUpIntent(this); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); + } else if (postDelete != null) { + postDelete.run(); } - } else { - deleteFromServer.setEnabled(true); - button.setText(R.string.delete); - button.setEnabled(true); - Toast.makeText(this,R.string.could_not_delete_account_from_server,Toast.LENGTH_LONG).show(); } }); - }); - } else { - Toast.makeText(this,R.string.not_connected_try_again,Toast.LENGTH_LONG).show(); - } - } else { - xmppConnectionService.deleteAccount(account); - dialog.dismiss(); - if (xmppConnectionService.getAccounts().size() == 0 && Config.MAGIC_CREATE_DOMAIN != null) { - final Intent intent = SignupUtils.getSignUpIntent(this); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - startActivity(intent); - } else if (postDelete != null) { - postDelete.run(); - } - } - }); - }); + }); dialog.show(); } @@ -403,61 +480,75 @@ public abstract class XmppActivity extends ActionBarActivity { protected void registerListeners() { if (this instanceof XmppConnectionService.OnConversationUpdate) { - this.xmppConnectionService.setOnConversationListChangedListener((XmppConnectionService.OnConversationUpdate) this); + this.xmppConnectionService.setOnConversationListChangedListener( + (XmppConnectionService.OnConversationUpdate) this); } if (this instanceof XmppConnectionService.OnAccountUpdate) { - this.xmppConnectionService.setOnAccountListChangedListener((XmppConnectionService.OnAccountUpdate) this); + this.xmppConnectionService.setOnAccountListChangedListener( + (XmppConnectionService.OnAccountUpdate) this); } if (this instanceof XmppConnectionService.OnCaptchaRequested) { - this.xmppConnectionService.setOnCaptchaRequestedListener((XmppConnectionService.OnCaptchaRequested) this); + this.xmppConnectionService.setOnCaptchaRequestedListener( + (XmppConnectionService.OnCaptchaRequested) this); } if (this instanceof XmppConnectionService.OnRosterUpdate) { - this.xmppConnectionService.setOnRosterUpdateListener((XmppConnectionService.OnRosterUpdate) this); + this.xmppConnectionService.setOnRosterUpdateListener( + (XmppConnectionService.OnRosterUpdate) this); } if (this instanceof XmppConnectionService.OnMucRosterUpdate) { - this.xmppConnectionService.setOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this); + this.xmppConnectionService.setOnMucRosterUpdateListener( + (XmppConnectionService.OnMucRosterUpdate) this); } if (this instanceof OnUpdateBlocklist) { this.xmppConnectionService.setOnUpdateBlocklistListener((OnUpdateBlocklist) this); } if (this instanceof XmppConnectionService.OnShowErrorToast) { - this.xmppConnectionService.setOnShowErrorToastListener((XmppConnectionService.OnShowErrorToast) this); + this.xmppConnectionService.setOnShowErrorToastListener( + (XmppConnectionService.OnShowErrorToast) this); } if (this instanceof OnKeyStatusUpdated) { this.xmppConnectionService.setOnKeyStatusUpdatedListener((OnKeyStatusUpdated) this); } if (this instanceof XmppConnectionService.OnJingleRtpConnectionUpdate) { - this.xmppConnectionService.setOnRtpConnectionUpdateListener((XmppConnectionService.OnJingleRtpConnectionUpdate) this); + this.xmppConnectionService.setOnRtpConnectionUpdateListener( + (XmppConnectionService.OnJingleRtpConnectionUpdate) this); } } protected void unregisterListeners() { if (this instanceof XmppConnectionService.OnConversationUpdate) { - this.xmppConnectionService.removeOnConversationListChangedListener((XmppConnectionService.OnConversationUpdate) this); + this.xmppConnectionService.removeOnConversationListChangedListener( + (XmppConnectionService.OnConversationUpdate) this); } if (this instanceof XmppConnectionService.OnAccountUpdate) { - this.xmppConnectionService.removeOnAccountListChangedListener((XmppConnectionService.OnAccountUpdate) this); + this.xmppConnectionService.removeOnAccountListChangedListener( + (XmppConnectionService.OnAccountUpdate) this); } if (this instanceof XmppConnectionService.OnCaptchaRequested) { - this.xmppConnectionService.removeOnCaptchaRequestedListener((XmppConnectionService.OnCaptchaRequested) this); + this.xmppConnectionService.removeOnCaptchaRequestedListener( + (XmppConnectionService.OnCaptchaRequested) this); } if (this instanceof XmppConnectionService.OnRosterUpdate) { - this.xmppConnectionService.removeOnRosterUpdateListener((XmppConnectionService.OnRosterUpdate) this); + this.xmppConnectionService.removeOnRosterUpdateListener( + (XmppConnectionService.OnRosterUpdate) this); } if (this instanceof XmppConnectionService.OnMucRosterUpdate) { - this.xmppConnectionService.removeOnMucRosterUpdateListener((XmppConnectionService.OnMucRosterUpdate) this); + this.xmppConnectionService.removeOnMucRosterUpdateListener( + (XmppConnectionService.OnMucRosterUpdate) this); } if (this instanceof OnUpdateBlocklist) { this.xmppConnectionService.removeOnUpdateBlocklistListener((OnUpdateBlocklist) this); } if (this instanceof XmppConnectionService.OnShowErrorToast) { - this.xmppConnectionService.removeOnShowErrorToastListener((XmppConnectionService.OnShowErrorToast) this); + this.xmppConnectionService.removeOnShowErrorToastListener( + (XmppConnectionService.OnShowErrorToast) this); } if (this instanceof OnKeyStatusUpdated) { this.xmppConnectionService.removeOnNewKeysAvailableListener((OnKeyStatusUpdated) this); } if (this instanceof XmppConnectionService.OnJingleRtpConnectionUpdate) { - this.xmppConnectionService.removeRtpConnectionUpdateListener((XmppConnectionService.OnJingleRtpConnectionUpdate) this); + this.xmppConnectionService.removeRtpConnectionUpdateListener( + (XmppConnectionService.OnJingleRtpConnectionUpdate) this); } } @@ -465,7 +556,9 @@ public abstract class XmppActivity extends ActionBarActivity { public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.action_settings: - startActivity(new Intent(this, eu.siacs.conversations.ui.activity.SettingsActivity.class)); + startActivity( + new Intent( + this, eu.siacs.conversations.ui.activity.SettingsActivity.class)); break; case R.id.action_privacy_policy: openPrivacyPolicy(); @@ -500,7 +593,8 @@ public abstract class XmppActivity extends ActionBarActivity { } } - public void selectPresence(final Conversation conversation, final PresenceSelector.OnPresenceSelected listener) { + public void selectPresence( + final Conversation conversation, final PresenceSelector.OnPresenceSelected listener) { final Contact contact = conversation.getContact(); if (contact.showInRoster() || contact.isSelf()) { final Presences presences = contact.getPresences(); @@ -521,7 +615,8 @@ public abstract class XmppActivity extends ActionBarActivity { } } else if (presences.size() == 1) { final String presence = presences.toResourceArray()[0]; - conversation.setNextCounterpart(PresenceSelector.getNextCounterpart(contact, presence)); + conversation.setNextCounterpart( + PresenceSelector.getNextCounterpart(contact, presence)); listener.onPresenceSelected(); } else { PresenceSelector.showPresenceSelectionDialog(this, conversation, listener); @@ -536,7 +631,8 @@ public abstract class XmppActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); metrics = getResources().getDisplayMetrics(); - this.isCameraFeatureAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY); + this.isCameraFeatureAvailable = + getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY); } protected boolean isCameraFeatureAvailable() { @@ -546,14 +642,16 @@ public abstract class XmppActivity extends ActionBarActivity { protected boolean isOptimizingBattery() { final PowerManager pm = getSystemService(PowerManager.class); return !pm.isIgnoringBatteryOptimizations(getPackageName()); -} + } protected boolean isAffectedByDataSaver() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - final ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + final ConnectivityManager cm = + (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); return cm != null && cm.isActiveNetworkMetered() - && Compatibility.getRestrictBackgroundStatus(cm) == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; + && Compatibility.getRestrictBackgroundStatus(cm) + == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; } else { return false; } @@ -564,7 +662,8 @@ public abstract class XmppActivity extends ActionBarActivity { } private boolean useTor() { - return QuickConversationsService.isConversations() && getBooleanPreference("use_tor", R.bool.use_tor); + return QuickConversationsService.isConversations() + && getBooleanPreference("use_tor", R.bool.use_tor); } protected SharedPreferences getPreferences() { @@ -599,7 +698,13 @@ public abstract class XmppActivity extends ActionBarActivity { switchToConversation(conversation, null, false, nick, true, false); } - private void switchToConversation(Conversation conversation, String text, boolean asQuote, String nick, boolean pm, boolean doNotAppend) { + private void switchToConversation( + Conversation conversation, + String text, + boolean asQuote, + String nick, + boolean pm, + boolean doNotAppend) { Intent intent = new Intent(this, ConversationsActivity.class); intent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION); intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid()); @@ -647,7 +752,10 @@ public abstract class XmppActivity extends ActionBarActivity { intent.putExtra("jid", account.getJid().asBareJid().toEscapedString()); intent.putExtra("init", init); if (init) { - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION); + intent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION); } if (fingerprint != null) { intent.putExtra("fingerprint", fingerprint); @@ -671,85 +779,113 @@ public abstract class XmppActivity extends ActionBarActivity { } protected void inviteToConversation(Conversation conversation) { - startActivityForResult(ChooseContactActivity.create(this, conversation), REQUEST_INVITE_TO_CONVERSATION); + startActivityForResult( + ChooseContactActivity.create(this, conversation), REQUEST_INVITE_TO_CONVERSATION); } - protected void announcePgp(final Account account, final Conversation conversation, Intent intent, final Runnable onSuccess) { + protected void announcePgp( + final Account account, + final Conversation conversation, + Intent intent, + final Runnable onSuccess) { if (account.getPgpId() == 0) { choosePgpSignId(account); } else { final String status = Strings.nullToEmpty(account.getPresenceStatusMessage()); - xmppConnectionService.getPgpEngine().generateSignature(intent, account, status, new UiCallback() { - - @Override - public void userInputRequired(final PendingIntent pi, final String signature) { - try { - startIntentSenderForResult(pi.getIntentSender(), REQUEST_ANNOUNCE_PGP, null, 0, 0, 0,Compatibility.pgpStartIntentSenderOptions()); - } catch (final SendIntentException ignored) { - } - } + xmppConnectionService + .getPgpEngine() + .generateSignature( + intent, + account, + status, + new UiCallback() { + + @Override + public void userInputRequired( + final PendingIntent pi, final String signature) { + try { + startIntentSenderForResult( + pi.getIntentSender(), + REQUEST_ANNOUNCE_PGP, + null, + 0, + 0, + 0, + Compatibility.pgpStartIntentSenderOptions()); + } catch (final SendIntentException ignored) { + } + } - @Override - public void success(String signature) { - account.setPgpSignature(signature); - xmppConnectionService.databaseBackend.updateAccount(account); - xmppConnectionService.sendPresence(account); - if (conversation != null) { - conversation.setNextEncryption(Message.ENCRYPTION_PGP); - xmppConnectionService.updateConversation(conversation); - refreshUi(); - } - if (onSuccess != null) { - runOnUiThread(onSuccess); - } - } + @Override + public void success(String signature) { + account.setPgpSignature(signature); + xmppConnectionService.databaseBackend.updateAccount(account); + xmppConnectionService.sendPresence(account); + if (conversation != null) { + conversation.setNextEncryption(Message.ENCRYPTION_PGP); + xmppConnectionService.updateConversation(conversation); + refreshUi(); + } + if (onSuccess != null) { + runOnUiThread(onSuccess); + } + } - @Override - public void error(int error, String signature) { - if (error == 0) { - account.setPgpSignId(0); - account.unsetPgpSignature(); - xmppConnectionService.databaseBackend.updateAccount(account); - choosePgpSignId(account); - } else { - displayErrorDialog(error); - } - } - }); + @Override + public void error(int error, String signature) { + if (error == 0) { + account.setPgpSignId(0); + account.unsetPgpSignature(); + xmppConnectionService.databaseBackend.updateAccount( + account); + choosePgpSignId(account); + } else { + displayErrorDialog(error); + } + } + }); } } protected void choosePgpSignId(final Account account) { - xmppConnectionService.getPgpEngine().chooseKey(account, new UiCallback<>() { - @Override - public void success(final Account a) { - } - - @Override - public void error(int errorCode, Account object) { - - } - - @Override - public void userInputRequired(PendingIntent pi, Account object) { - try { - startIntentSenderForResult(pi.getIntentSender(), - REQUEST_CHOOSE_PGP_ID, null, 0, 0, 0, Compatibility.pgpStartIntentSenderOptions()); - } catch (final SendIntentException ignored) { - } - } - }); + xmppConnectionService + .getPgpEngine() + .chooseKey( + account, + new UiCallback<>() { + @Override + public void success(final Account a) {} + + @Override + public void error(int errorCode, Account object) {} + + @Override + public void userInputRequired(PendingIntent pi, Account object) { + try { + startIntentSenderForResult( + pi.getIntentSender(), + REQUEST_CHOOSE_PGP_ID, + null, + 0, + 0, + 0, + Compatibility.pgpStartIntentSenderOptions()); + } catch (final SendIntentException ignored) { + } + } + }); } protected void displayErrorDialog(final int errorCode) { - runOnUiThread(() -> { - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(XmppActivity.this); - builder.setTitle(getString(R.string.error)); - builder.setMessage(errorCode); - builder.setNeutralButton(R.string.accept, null); - builder.create().show(); - }); - + runOnUiThread( + () -> { + final MaterialAlertDialogBuilder builder = + new MaterialAlertDialogBuilder(XmppActivity.this); + builder.setTitle(getString(R.string.error)); + builder.setMessage(errorCode); + builder.setNeutralButton(R.string.accept, null); + builder.create().show(); + }); } protected void showAddToRosterDialog(final Contact contact) { @@ -757,7 +893,9 @@ public abstract class XmppActivity extends ActionBarActivity { builder.setTitle(contact.getJid().toString()); builder.setMessage(getString(R.string.not_in_roster)); builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.add_contact), (dialog, which) -> xmppConnectionService.createContact(contact, true)); + builder.setPositiveButton( + getString(R.string.add_contact), + (dialog, which) -> xmppConnectionService.createContact(contact, true)); builder.create().show(); } @@ -766,13 +904,15 @@ public abstract class XmppActivity extends ActionBarActivity { builder.setTitle(contact.getJid().toString()); builder.setMessage(R.string.request_presence_updates); builder.setNegativeButton(R.string.cancel, null); - builder.setPositiveButton(R.string.request_now, + builder.setPositiveButton( + R.string.request_now, (dialog, which) -> { if (xmppConnectionServiceBound) { - xmppConnectionService.sendPresencePacket(contact - .getAccount(), xmppConnectionService - .getPresenceGenerator() - .requestPresenceUpdatesFrom(contact)); + xmppConnectionService.sendPresencePacket( + contact.getAccount(), + xmppConnectionService + .getPresenceGenerator() + .requestPresenceUpdatesFrom(contact)); } }); builder.create().show(); @@ -782,7 +922,11 @@ public abstract class XmppActivity extends ActionBarActivity { quickEdit(previousValue, callback, hint, false, false); } - protected void quickEdit(String previousValue, @StringRes int hint, OnValueEdited callback, boolean permitEmpty) { + protected void quickEdit( + String previousValue, + @StringRes int hint, + OnValueEdited callback, + boolean permitEmpty) { quickEdit(previousValue, callback, hint, false, permitEmpty); } @@ -791,15 +935,19 @@ public abstract class XmppActivity extends ActionBarActivity { } @SuppressLint("InflateParams") - private void quickEdit(final String previousValue, - final OnValueEdited callback, - final @StringRes int hint, - boolean password, - boolean permitEmpty) { + private void quickEdit( + final String previousValue, + final OnValueEdited callback, + final @StringRes int hint, + boolean password, + boolean permitEmpty) { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); - final DialogQuickeditBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_quickedit, null, false); + final DialogQuickeditBinding binding = + DataBindingUtil.inflate( + getLayoutInflater(), R.layout.dialog_quickedit, null, false); if (password) { - binding.inputEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); + binding.inputEditText.setInputType( + InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); } builder.setPositiveButton(R.string.accept, null); if (hint != 0) { @@ -814,33 +962,39 @@ public abstract class XmppActivity extends ActionBarActivity { final AlertDialog dialog = builder.create(); dialog.setOnShowListener(d -> SoftKeyboardUtils.showKeyboard(binding.inputEditText)); dialog.show(); - View.OnClickListener clickListener = v -> { - String value = binding.inputEditText.getText().toString(); - if (!value.equals(previousValue) && (!value.trim().isEmpty() || permitEmpty)) { - String error = callback.onValueEdited(value); - if (error != null) { - binding.inputLayout.setError(error); - return; - } - } - SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); - dialog.dismiss(); - }; + View.OnClickListener clickListener = + v -> { + String value = binding.inputEditText.getText().toString(); + if (!value.equals(previousValue) && (!value.trim().isEmpty() || permitEmpty)) { + String error = callback.onValueEdited(value); + if (error != null) { + binding.inputLayout.setError(error); + return; + } + } + SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); + dialog.dismiss(); + }; dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(clickListener); - dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener((v -> { - SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); - dialog.dismiss(); - })); + dialog.getButton(DialogInterface.BUTTON_NEGATIVE) + .setOnClickListener( + (v -> { + SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); + dialog.dismiss(); + })); dialog.setCanceledOnTouchOutside(false); - dialog.setOnDismissListener(dialog1 -> { - SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); - }); + dialog.setOnDismissListener( + dialog1 -> { + SoftKeyboardUtils.hideSoftKeyboard(binding.inputEditText); + }); } protected boolean hasStoragePermission(int requestCode) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode); + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + requestPermissions( + new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestCode); return false; } else { return true; @@ -876,7 +1030,8 @@ public abstract class XmppActivity extends ActionBarActivity { } protected boolean manuallyChangePresence() { - return getBooleanPreference(AppSettings.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence); + return getBooleanPreference( + AppSettings.MANUALLY_CHANGE_PRESENCE, R.bool.manually_change_presence); } protected String getShareableUri() { @@ -906,16 +1061,21 @@ public abstract class XmppActivity extends ActionBarActivity { PgpEngine pgp = XmppActivity.this.xmppConnectionService.getPgpEngine(); try { startIntentSenderForResult( - pgp.getIntentForKey(keyId).getIntentSender(), 0, null, 0, - 0, 0, Compatibility.pgpStartIntentSenderOptions()); + pgp.getIntentForKey(keyId).getIntentSender(), + 0, + null, + 0, + 0, + 0, + Compatibility.pgpStartIntentSenderOptions()); } catch (final Throwable e) { - Log.d(Config.LOGTAG,"could not launch OpenKeyChain", e); + Log.d(Config.LOGTAG, "could not launch OpenKeyChain", e); Toast.makeText(XmppActivity.this, R.string.openpgp_error, Toast.LENGTH_SHORT).show(); } } @Override - protected void onResume(){ + protected void onResume() { super.onResume(); SettingsUtils.applyScreenshotSetting(this); } @@ -947,11 +1107,27 @@ public abstract class XmppActivity extends ActionBarActivity { final int black; final int white; if (Activities.isNightMode(this)) { - black = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceContainerHighest,"No surface color configured"); - white = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceInverse,"No inverse surface color configured"); + black = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurfaceContainerHighest, + "No surface color configured"); + white = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurfaceInverse, + "No inverse surface color configured"); } else { - black = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceInverse,"No inverse surface color configured"); - white = MaterialColors.getColor(this, com.google.android.material.R.attr.colorSurfaceContainerHighest,"No surface color configured"); + black = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurfaceInverse, + "No inverse surface color configured"); + white = + MaterialColors.getColor( + this, + com.google.android.material.R.attr.colorSurfaceContainerHighest, + "No surface color configured"); } final var bitmap = BarcodeProvider.create2dBarcodeBitmap(uri, width, black, white); final ImageView view = new ImageView(this); @@ -978,7 +1154,10 @@ public abstract class XmppActivity extends ActionBarActivity { public void loadBitmap(Message message, ImageView imageView) { Bitmap bm; try { - bm = xmppConnectionService.getFileBackend().getThumbnail(message, (int) (metrics.density * 288), true); + bm = + xmppConnectionService + .getFileBackend() + .getThumbnail(message, (int) (metrics.density * 288), true); } catch (IOException e) { bm = null; } @@ -991,8 +1170,7 @@ public abstract class XmppActivity extends ActionBarActivity { imageView.setBackgroundColor(0xff333333); imageView.setImageDrawable(null); final BitmapWorkerTask task = new BitmapWorkerTask(imageView); - final AsyncDrawable asyncDrawable = new AsyncDrawable( - getResources(), null, task); + final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), null, task); imageView.setImageDrawable(asyncDrawable); try { task.execute(message); @@ -1035,7 +1213,8 @@ public abstract class XmppActivity extends ActionBarActivity { return false; } else { jids.add(conversation.getJid().asBareJid()); - return service.createAdhocConference(conversation.getAccount(), null, jids, activity.adhocCallback); + return service.createAdhocConference( + conversation.getAccount(), null, jids, activity.adhocCallback); } } } @@ -1057,7 +1236,9 @@ public abstract class XmppActivity extends ActionBarActivity { try { final XmppActivity activity = find(imageViewReference); if (activity != null && activity.xmppConnectionService != null) { - return activity.xmppConnectionService.getFileBackend().getThumbnail(message, (int) (activity.metrics.density * 288), false); + return activity.xmppConnectionService + .getFileBackend() + .getThumbnail(message, (int) (activity.metrics.density * 288), false); } else { return null; } diff --git a/src/main/res/menu/contact_details.xml b/src/main/res/menu/contact_details.xml index c7d330d11e813f92a124dd600e6fbdc84ee061df..6a851d8b4302b82f7037d53fbe1266a156a270af 100644 --- a/src/main/res/menu/contact_details.xml +++ b/src/main/res/menu/contact_details.xml @@ -1,64 +1,70 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + android:title="@string/action_edit_contact" + app:showAsAction="always" /> + android:title="@string/share_uri_with" + app:showAsAction="always"> + android:title="@string/share_as_uri" /> + android:title="@string/share_as_http" /> + android:title="@string/show_qr_code" /> + android:title="@string/action_delete_contact" + app:showAsAction="never" /> + android:title="@string/action_block_contact" + app:showAsAction="never" /> + android:title="@string/action_unblock_contact" + app:showAsAction="never" /> + + + android:title="@string/action_accounts" + app:showAsAction="never" /> + app:showAsAction="never" /> + android:title="@string/action_settings" + app:showAsAction="never" /> \ No newline at end of file diff --git a/src/main/res/menu/muc_details.xml b/src/main/res/menu/muc_details.xml index 4c515ce67184a79746218289108fc24c957511e9..81c58ff926313b2bc951996f38b2ff9173398206 100644 --- a/src/main/res/menu/muc_details.xml +++ b/src/main/res/menu/muc_details.xml @@ -1,57 +1,62 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> + android:title="@string/share_uri_with" + app:showAsAction="ifRoom"> + android:title="@string/share_as_uri" /> + android:title="@string/share_as_http" /> + android:title="@string/show_qr_code" /> + android:title="@string/save_as_bookmark" + app:showAsAction="never" /> + android:title="@string/destroy_room" + app:showAsAction="never" /> + android:title="@string/advanced_mode" + app:showAsAction="never" /> + + android:title="@string/action_accounts" + app:showAsAction="never" /> + app:showAsAction="never" /> + android:title="@string/action_settings" + app:showAsAction="never" /> \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index fde70c71b2b38622e5a594693a14da759a18300e..5a46d0910681036a3e51d2291aab44719ce272fa 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1097,4 +1097,6 @@ Calls from this app interact with regular phone calls, such as ending one call when another starts. Left-aligned messages Display all messages, including sent ones, on the left side for a uniform chat layout. + Custom notifications + Enable customized notification settings (importance, sound, vibration) settings for this conversation?