apply Material 3 theme to all activites

Daniel Gultsch created

Change summary

build.gradle                                                                        |   2 
src/conversations/AndroidManifest.xml                                               |   1 
src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java     |   4 
src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java  |  68 
src/conversations/java/eu/siacs/conversations/ui/ImportBackupActivity.java          |  21 
src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java           | 141 
src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java         | 111 
src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java            |  15 
src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java       |   9 
src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java               |  94 
src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java     |  13 
src/conversations/res/drawable-hdpi/ic_unarchive_white_24dp.png                     |   0 
src/conversations/res/drawable-mdpi/ic_unarchive_white_24dp.png                     |   0 
src/conversations/res/drawable-xhdpi/ic_unarchive_white_24dp.png                    |   0 
src/conversations/res/drawable-xxhdpi/ic_unarchive_white_24dp.png                   |   0 
src/conversations/res/drawable-xxxhdpi/ic_unarchive_white_24dp.png                  |   0 
src/conversations/res/layout/activity_easy_invite.xml                               |  32 
src/conversations/res/layout/activity_import_backup.xml                             |  27 
src/conversations/res/layout/activity_magic_create.xml                              |  54 
src/conversations/res/layout/activity_pick_server.xml                               |  38 
src/conversations/res/layout/activity_welcome.xml                                   |  41 
src/conversations/res/layout/dialog_enter_password.xml                              |  32 
src/conversations/res/menu/easy_onboarding_invite.xml                               |   2 
src/conversations/res/menu/manageaccounts.xml                                       |  53 
src/conversations/res/menu/welcome_menu.xml                                         |   2 
src/conversations/res/values/colors-themed.xml                                      |  63 
src/main/AndroidManifest.xml                                                        |  28 
src/main/java/eu/siacs/conversations/Config.java                                    |   2 
src/main/java/eu/siacs/conversations/Conversations.java                             |  67 
src/main/java/eu/siacs/conversations/entities/RtpSessionStatus.java                 |  10 
src/main/java/eu/siacs/conversations/services/BarcodeProvider.java                  |  10 
src/main/java/eu/siacs/conversations/services/ExportBackupService.java              |   6 
src/main/java/eu/siacs/conversations/services/NotificationService.java              |  57 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java            |   3 
src/main/java/eu/siacs/conversations/ui/AboutActivity.java                          |  22 
src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java     |   6 
src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java                      |   2 
src/main/java/eu/siacs/conversations/ui/Activities.java                             |  47 
src/main/java/eu/siacs/conversations/ui/BaseActivity.java                           |  53 
src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java                     |   4 
src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java                 |  98 
src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java               |  28 
src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java |  25 
src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java                  |  24 
src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java              |  47 
src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java                 |  32 
src/main/java/eu/siacs/conversations/ui/ConversationActivity.java                   |   6 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java                   |  24 
src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java                  |  45 
src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java          |  12 
src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java           |  12 
src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java              |  25 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java                    |  45 
src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java                         |  58 
src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java                   |   9 
src/main/java/eu/siacs/conversations/ui/LocationActivity.java                       |   5 
src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java                   |   1 
src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java                     |   8 
src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java                       |   3 
src/main/java/eu/siacs/conversations/ui/OmemoActivity.java                          |  20 
src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java |   2 
src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java          |  15 
src/main/java/eu/siacs/conversations/ui/RecordingActivity.java                      |  17 
src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java                     |  37 
src/main/java/eu/siacs/conversations/ui/ScanActivity.java                           |   1 
src/main/java/eu/siacs/conversations/ui/SearchActivity.java                         |  18 
src/main/java/eu/siacs/conversations/ui/SettingsActivity.java                       |  90 
src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java                  |  39 
src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java                      | 120 
src/main/java/eu/siacs/conversations/ui/ShortcutActivity.java                       |   2 
src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java                   |   2 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java              |  60 
src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java                      |  39 
src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java                     |   2 
src/main/java/eu/siacs/conversations/ui/XmppActivity.java                           |  95 
src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java                 |  26 
src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java     |  14 
src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java            | 115 
src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java              |  57 
src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java                |  30 
src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java                   | 180 
src/main/java/eu/siacs/conversations/ui/adapter/MediaPreviewAdapter.java            |  83 
src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java                 | 290 
src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java                    |  10 
src/main/java/eu/siacs/conversations/ui/adapter/UserPreviewAdapter.java             |  47 
src/main/java/eu/siacs/conversations/ui/forms/FormBooleanFieldWrapper.java          |  80 
src/main/java/eu/siacs/conversations/ui/forms/FormFieldFactory.java                 |  30 
src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java                 |  93 
src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java        |  43 
src/main/java/eu/siacs/conversations/ui/forms/FormTextFieldWrapper.java             |  97 
src/main/java/eu/siacs/conversations/ui/forms/FormWrapper.java                      |  72 
src/main/java/eu/siacs/conversations/ui/service/AudioPlayer.java                    | 170 
src/main/java/eu/siacs/conversations/ui/util/ActionBarUtil.java                     |  88 
src/main/java/eu/siacs/conversations/ui/util/Attachment.java                        |  83 
src/main/java/eu/siacs/conversations/ui/util/ConversationMenuConfigurator.java      |   8 
src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java       |   4 
src/main/java/eu/siacs/conversations/ui/util/PresenceSelector.java                  |   8 
src/main/java/eu/siacs/conversations/ui/util/SendButtonTool.java                    | 236 
src/main/java/eu/siacs/conversations/ui/util/StyledAttributes.java                  |  59 
src/main/java/eu/siacs/conversations/ui/util/ToolbarUtils.java                      | 166 
src/main/java/eu/siacs/conversations/ui/widget/ImmediateAutoCompleteTextView.java   |   4 
src/main/java/eu/siacs/conversations/ui/widget/ScannerView.java                     |  19 
src/main/java/eu/siacs/conversations/ui/widget/SwipeRefreshListFragment.java        |   5 
src/main/java/eu/siacs/conversations/ui/widget/UnreadCountCustomView.java           |   9 
src/main/java/eu/siacs/conversations/utils/AccountUtils.java                        |   6 
src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java                     |   7 
src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java            |   7 
src/main/java/eu/siacs/conversations/utils/MimeUtils.java                           |   2 
src/main/java/eu/siacs/conversations/utils/StylingHelper.java                       |  44 
src/main/java/eu/siacs/conversations/utils/ThemeHelper.java                         | 117 
src/main/res/drawable-hdpi/baseline_tour_black_48.png                               |   0 
src/main/res/drawable-hdpi/baseline_tour_white_48.png                               |   0 
src/main/res/drawable-hdpi/date_bubble_grey.9.png                                   |   0 
src/main/res/drawable-hdpi/date_bubble_white.9.png                                  |   0 
src/main/res/drawable-hdpi/ic_account_box_white_24dp.png                            |   0 
src/main/res/drawable-hdpi/ic_action_reply.png                                      |   0 
src/main/res/drawable-hdpi/ic_add_white_24dp.png                                    |   0 
src/main/res/drawable-hdpi/ic_android_black_48dp.png                                |   0 
src/main/res/drawable-hdpi/ic_android_white_48dp.png                                |   0 
src/main/res/drawable-hdpi/ic_announcement_white_24dp.png                           |   0 
src/main/res/drawable-hdpi/ic_archive_black_48dp.png                                |   0 
src/main/res/drawable-hdpi/ic_archive_white_24dp.png                                |   0 
src/main/res/drawable-hdpi/ic_archive_white_48dp.png                                |   0 
src/main/res/drawable-hdpi/ic_attach_camera.png                                     |   0 
src/main/res/drawable-hdpi/ic_attach_camera_white.png                               |   0 
src/main/res/drawable-hdpi/ic_attach_document.png                                   |   0 
src/main/res/drawable-hdpi/ic_attach_document_white.png                             |   0 
src/main/res/drawable-hdpi/ic_attach_file_white_24dp.png                            |   0 
src/main/res/drawable-hdpi/ic_attach_location.png                                   |   0 
src/main/res/drawable-hdpi/ic_attach_location_white.png                             |   0 
src/main/res/drawable-hdpi/ic_attach_photo.png                                      |   0 
src/main/res/drawable-hdpi/ic_attach_photo_white.png                                |   0 
src/main/res/drawable-hdpi/ic_attach_record.png                                     |   0 
src/main/res/drawable-hdpi/ic_attach_record_white.png                               |   0 
src/main/res/drawable-hdpi/ic_attach_videocam.png                                   |   0 
src/main/res/drawable-hdpi/ic_attach_videocam_white.png                             |   0 
src/main/res/drawable-hdpi/ic_autorenew_white_24dp.png                              |   0 
src/main/res/drawable-hdpi/ic_backup_black_48dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_backup_white_48dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_block_white_24dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_bluetooth_audio_black_24dp.png                        |   0 
src/main/res/drawable-hdpi/ic_book_black_48dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_book_white_48dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_call_black_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_call_end_white_48dp.png                               |   0 
src/main/res/drawable-hdpi/ic_call_made_black_18dp.png                              |   0 
src/main/res/drawable-hdpi/ic_call_made_white_18dp.png                              |   0 
src/main/res/drawable-hdpi/ic_call_missed_black_18dp.png                            |   0 
src/main/res/drawable-hdpi/ic_call_missed_outgoing_black_18dp.png                   |   0 
src/main/res/drawable-hdpi/ic_call_missed_outgoing_white_18dp.png                   |   0 
src/main/res/drawable-hdpi/ic_call_missed_white_18dp.png                            |   0 
src/main/res/drawable-hdpi/ic_call_received_black_18dp.png                          |   0 
src/main/res/drawable-hdpi/ic_call_received_white_18dp.png                          |   0 
src/main/res/drawable-hdpi/ic_call_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_call_white_48dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_camera_alt_white_24dp.png                             |   0 
src/main/res/drawable-hdpi/ic_cancel_black_24dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_cancel_white_24dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_chat_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_clear_white_48dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_cloud_download_white_24dp.png                         |   0 
src/main/res/drawable-hdpi/ic_content_copy_white_24dp.png                           |   0 
src/main/res/drawable-hdpi/ic_crop_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_delete_black_24dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_delete_white_24dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_description_black_48dp.png                            |   0 
src/main/res/drawable-hdpi/ic_description_white_48dp.png                            |   0 
src/main/res/drawable-hdpi/ic_directions_black_24dp.png                             |   0 
src/main/res/drawable-hdpi/ic_directions_white_24dp.png                             |   0 
src/main/res/drawable-hdpi/ic_done_black_18dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_done_white_18dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_drafts_white_24dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_edit_black_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_edit_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_error_white_24dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_event_black_48dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_event_white_48dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_file_download_white_24dp.png                          |   0 
src/main/res/drawable-hdpi/ic_flip_camera_android_black_24dp.png                    |   0 
src/main/res/drawable-hdpi/ic_forward_white_24dp.png                                |   0 
src/main/res/drawable-hdpi/ic_gps_fixed_black_24dp.png                              |   0 
src/main/res/drawable-hdpi/ic_gps_fixed_white_24dp.png                              |   0 
src/main/res/drawable-hdpi/ic_gps_not_fixed_black_24dp.png                          |   0 
src/main/res/drawable-hdpi/ic_gps_not_fixed_white_24dp.png                          |   0 
src/main/res/drawable-hdpi/ic_group_add_white_24dp.png                              |   0 
src/main/res/drawable-hdpi/ic_group_white_24dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_headset_black_24dp.png                                |   0 
src/main/res/drawable-hdpi/ic_headset_black_48dp.png                                |   0 
src/main/res/drawable-hdpi/ic_headset_white_48dp.png                                |   0 
src/main/res/drawable-hdpi/ic_help_black_48dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_help_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_help_white_48dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_hourglass_empty_white_24dp.png                        |   0 
src/main/res/drawable-hdpi/ic_image_black_48dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_image_white_48dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_input_white_24dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_link_off_white_24dp.png                               |   0 
src/main/res/drawable-hdpi/ic_link_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_lock_black_18dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_lock_open_white_24dp.png                              |   0 
src/main/res/drawable-hdpi/ic_lock_white_18dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_lock_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_mic_black_24dp.png                                    |   0 
src/main/res/drawable-hdpi/ic_mic_black_48dp.png                                    |   0 
src/main/res/drawable-hdpi/ic_mic_off_black_24dp.png                                |   0 
src/main/res/drawable-hdpi/ic_mic_white_48dp.png                                    |   0 
src/main/res/drawable-hdpi/ic_mode_edit_black_18dp.png                              |   0 
src/main/res/drawable-hdpi/ic_mode_edit_white_18dp.png                              |   0 
src/main/res/drawable-hdpi/ic_new_releases_black_24dp.png                           |   0 
src/main/res/drawable-hdpi/ic_new_releases_white_24dp.png                           |   0 
src/main/res/drawable-hdpi/ic_no_results_background_black.png                       |   0 
src/main/res/drawable-hdpi/ic_no_results_background_white.png                       |   0 
src/main/res/drawable-hdpi/ic_notifications_black_24dp.png                          |   0 
src/main/res/drawable-hdpi/ic_notifications_none_black_24dp.png                     |   0 
src/main/res/drawable-hdpi/ic_notifications_none_white80.png                        |   0 
src/main/res/drawable-hdpi/ic_notifications_none_white_24dp.png                     |   0 
src/main/res/drawable-hdpi/ic_notifications_off_black_24dp.png                      |   0 
src/main/res/drawable-hdpi/ic_notifications_off_white80.png                         |   0 
src/main/res/drawable-hdpi/ic_notifications_off_white_24dp.png                      |   0 
src/main/res/drawable-hdpi/ic_notifications_paused_black_24dp.png                   |   0 
src/main/res/drawable-hdpi/ic_notifications_paused_white80.png                      |   0 
src/main/res/drawable-hdpi/ic_notifications_paused_white_24dp.png                   |   0 
src/main/res/drawable-hdpi/ic_notifications_white80.png                             |   0 
src/main/res/drawable-hdpi/ic_notifications_white_24dp.png                          |   0 
src/main/res/drawable-hdpi/ic_pause_black_36dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_pause_white_36dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_person_add_white_24dp.png                             |   0 
src/main/res/drawable-hdpi/ic_person_black_48dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_person_white_48dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_phone_in_talk_black_18dp.png                          |   0 
src/main/res/drawable-hdpi/ic_phone_in_talk_white_18dp.png                          |   0 
src/main/res/drawable-hdpi/ic_phone_in_talk_white_24dp.png                          |   0 
src/main/res/drawable-hdpi/ic_play_arrow_black_36dp.png                             |   0 
src/main/res/drawable-hdpi/ic_play_arrow_white_36dp.png                             |   0 
src/main/res/drawable-hdpi/ic_play_circle_filled_white_48dp.png                     |   0 
src/main/res/drawable-hdpi/ic_profile.png                                           |   0 
src/main/res/drawable-hdpi/ic_public_white_24dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_qr_code_scan_white_24dp.png                           |   0 
src/main/res/drawable-hdpi/ic_question_answer_white_24dp.png                        |   0 
src/main/res/drawable-hdpi/ic_refresh_black_24dp.png                                |   0 
src/main/res/drawable-hdpi/ic_refresh_white_24dp.png                                |   0 
src/main/res/drawable-hdpi/ic_replay_white_48dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_reply_white_24dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_room_black_48dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_room_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_room_white_48dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_save_black_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_save_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_search_background_black.png                           |   0 
src/main/res/drawable-hdpi/ic_search_background_white.png                           |   0 
src/main/res/drawable-hdpi/ic_search_white_24dp.png                                 |   0 
src/main/res/drawable-hdpi/ic_send_cancel_away.png                                  |   0 
src/main/res/drawable-hdpi/ic_send_cancel_dnd.png                                   |   0 
src/main/res/drawable-hdpi/ic_send_cancel_offline.png                               |   0 
src/main/res/drawable-hdpi/ic_send_cancel_offline_dark.png                          |   0 
src/main/res/drawable-hdpi/ic_send_cancel_offline_white.png                         |   0 
src/main/res/drawable-hdpi/ic_send_cancel_online.png                                |   0 
src/main/res/drawable-hdpi/ic_send_file_offline.png                                 |   0 
src/main/res/drawable-hdpi/ic_send_file_offline_white.png                           |   0 
src/main/res/drawable-hdpi/ic_send_location_away.png                                |   0 
src/main/res/drawable-hdpi/ic_send_location_dnd.png                                 |   0 
src/main/res/drawable-hdpi/ic_send_location_offline.png                             |   0 
src/main/res/drawable-hdpi/ic_send_location_offline_dark.png                        |   0 
src/main/res/drawable-hdpi/ic_send_location_offline_white.png                       |   0 
src/main/res/drawable-hdpi/ic_send_location_online.png                              |   0 
src/main/res/drawable-hdpi/ic_send_photo_away.png                                   |   0 
src/main/res/drawable-hdpi/ic_send_photo_dnd.png                                    |   0 
src/main/res/drawable-hdpi/ic_send_photo_offline.png                                |   0 
src/main/res/drawable-hdpi/ic_send_photo_offline_dark.png                           |   0 
src/main/res/drawable-hdpi/ic_send_photo_offline_white.png                          |   0 
src/main/res/drawable-hdpi/ic_send_photo_online.png                                 |   0 
src/main/res/drawable-hdpi/ic_send_picture_away.png                                 |   0 
src/main/res/drawable-hdpi/ic_send_picture_dnd.png                                  |   0 
src/main/res/drawable-hdpi/ic_send_picture_offline.png                              |   0 
src/main/res/drawable-hdpi/ic_send_picture_offline_dark.png                         |   0 
src/main/res/drawable-hdpi/ic_send_picture_offline_white.png                        |   0 
src/main/res/drawable-hdpi/ic_send_picture_online.png                               |   0 
src/main/res/drawable-hdpi/ic_send_text_away.png                                    |   0 
src/main/res/drawable-hdpi/ic_send_text_dnd.png                                     |   0 
src/main/res/drawable-hdpi/ic_send_text_offline.png                                 |   0 
src/main/res/drawable-hdpi/ic_send_text_offline_dark.png                            |   0 
src/main/res/drawable-hdpi/ic_send_text_offline_white.png                           |   0 
src/main/res/drawable-hdpi/ic_send_text_online.png                                  |   0 
src/main/res/drawable-hdpi/ic_send_videocam_away.png                                |   0 
src/main/res/drawable-hdpi/ic_send_videocam_dnd.png                                 |   0 
src/main/res/drawable-hdpi/ic_send_videocam_offline.png                             |   0 
src/main/res/drawable-hdpi/ic_send_videocam_offline_white.png                       |   0 
src/main/res/drawable-hdpi/ic_send_videocam_online.png                              |   0 
src/main/res/drawable-hdpi/ic_send_voice_away.png                                   |   0 
src/main/res/drawable-hdpi/ic_send_voice_dnd.png                                    |   0 
src/main/res/drawable-hdpi/ic_send_voice_offline.png                                |   0 
src/main/res/drawable-hdpi/ic_send_voice_offline_dark.png                           |   0 
src/main/res/drawable-hdpi/ic_send_voice_offline_white.png                          |   0 
src/main/res/drawable-hdpi/ic_send_voice_online.png                                 |   0 
src/main/res/drawable-hdpi/ic_settings_black_24dp.png                               |   0 
src/main/res/drawable-hdpi/ic_settings_white_24dp.png                               |   0 
src/main/res/drawable-hdpi/ic_share_white_24dp.png                                  |   0 
src/main/res/drawable-hdpi/ic_star_black_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_star_white_24dp.png                                   |   0 
src/main/res/drawable-hdpi/ic_stat_alert_warning.png                                |   0 
src/main/res/drawable-hdpi/ic_stat_communication_import_export.png                  |   0 
src/main/res/drawable-hdpi/ic_verified_fingerprint.png                              |   0 
src/main/res/drawable-hdpi/ic_verified_user_black_18dp.png                          |   0 
src/main/res/drawable-hdpi/ic_verified_user_white_18dp.png                          |   0 
src/main/res/drawable-hdpi/ic_videocam_black_24dp.png                               |   0 
src/main/res/drawable-hdpi/ic_videocam_off_black_24dp.png                           |   0 
src/main/res/drawable-hdpi/ic_videocam_white_24dp.png                               |   0 
src/main/res/drawable-hdpi/ic_voicemail_white_24dp.png                              |   0 
src/main/res/drawable-hdpi/ic_volume_off_black_24dp.png                             |   0 
src/main/res/drawable-hdpi/ic_volume_up_black_24dp.png                              |   0 
src/main/res/drawable-hdpi/ic_warning_white_24dp.png                                |   0 
src/main/res/drawable-hdpi/ic_warning_white_48dp.png                                |   0 
src/main/res/drawable-hdpi/ic_wear_reply.png                                        |   0 
src/main/res/drawable-hdpi/message_bubble_received.9.png                            |   0 
src/main/res/drawable-hdpi/message_bubble_received_dark.9.png                       |   0 
src/main/res/drawable-hdpi/message_bubble_received_grey.9.png                       |   0 
src/main/res/drawable-hdpi/message_bubble_received_warning.9.png                    |   0 
src/main/res/drawable-hdpi/message_bubble_received_white.9.png                      |   0 
src/main/res/drawable-hdpi/message_bubble_sent.9.png                                |   0 
src/main/res/drawable-hdpi/message_bubble_sent_grey.9.png                           |   0 
src/main/res/drawable-mdpi/baseline_tour_black_48.png                               |   0 
src/main/res/drawable-mdpi/baseline_tour_white_48.png                               |   0 
src/main/res/drawable-mdpi/date_bubble_grey.9.png                                   |   0 
src/main/res/drawable-mdpi/date_bubble_white.9.png                                  |   0 
src/main/res/drawable-mdpi/ic_account_box_white_24dp.png                            |   0 
src/main/res/drawable-mdpi/ic_action_reply.png                                      |   0 
src/main/res/drawable-mdpi/ic_add_white_24dp.png                                    |   0 
src/main/res/drawable-mdpi/ic_android_black_48dp.png                                |   0 
src/main/res/drawable-mdpi/ic_android_white_48dp.png                                |   0 
src/main/res/drawable-mdpi/ic_announcement_white_24dp.png                           |   0 
src/main/res/drawable-mdpi/ic_archive_black_48dp.png                                |   0 
src/main/res/drawable-mdpi/ic_archive_white_24dp.png                                |   0 
src/main/res/drawable-mdpi/ic_archive_white_48dp.png                                |   0 
src/main/res/drawable-mdpi/ic_attach_camera.png                                     |   0 
src/main/res/drawable-mdpi/ic_attach_camera_white.png                               |   0 
src/main/res/drawable-mdpi/ic_attach_document.png                                   |   0 
src/main/res/drawable-mdpi/ic_attach_document_white.png                             |   0 
src/main/res/drawable-mdpi/ic_attach_file_white_24dp.png                            |   0 
src/main/res/drawable-mdpi/ic_attach_location.png                                   |   0 
src/main/res/drawable-mdpi/ic_attach_location_white.png                             |   0 
src/main/res/drawable-mdpi/ic_attach_photo.png                                      |   0 
src/main/res/drawable-mdpi/ic_attach_photo_white.png                                |   0 
src/main/res/drawable-mdpi/ic_attach_record.png                                     |   0 
src/main/res/drawable-mdpi/ic_attach_record_white.png                               |   0 
src/main/res/drawable-mdpi/ic_attach_videocam.png                                   |   0 
src/main/res/drawable-mdpi/ic_attach_videocam_white.png                             |   0 
src/main/res/drawable-mdpi/ic_autorenew_white_24dp.png                              |   0 
src/main/res/drawable-mdpi/ic_backup_black_48dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_backup_white_48dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_block_white_24dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_bluetooth_audio_black_24dp.png                        |   0 
src/main/res/drawable-mdpi/ic_book_black_48dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_book_white_48dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_call_black_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_call_end_white_48dp.png                               |   0 
src/main/res/drawable-mdpi/ic_call_made_black_18dp.png                              |   0 
src/main/res/drawable-mdpi/ic_call_made_white_18dp.png                              |   0 
src/main/res/drawable-mdpi/ic_call_missed_black_18dp.png                            |   0 
src/main/res/drawable-mdpi/ic_call_missed_outgoing_black_18dp.png                   |   0 
src/main/res/drawable-mdpi/ic_call_missed_outgoing_white_18dp.png                   |   0 
src/main/res/drawable-mdpi/ic_call_missed_white_18dp.png                            |   0 
src/main/res/drawable-mdpi/ic_call_received_black_18dp.png                          |   0 
src/main/res/drawable-mdpi/ic_call_received_white_18dp.png                          |   0 
src/main/res/drawable-mdpi/ic_call_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_call_white_48dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_camera_alt_white_24dp.png                             |   0 
src/main/res/drawable-mdpi/ic_cancel_black_24dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_cancel_white_24dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_chat_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_clear_white_48dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_cloud_download_white_24dp.png                         |   0 
src/main/res/drawable-mdpi/ic_content_copy_white_24dp.png                           |   0 
src/main/res/drawable-mdpi/ic_crop_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_delete_black_24dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_delete_white_24dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_description_black_48dp.png                            |   0 
src/main/res/drawable-mdpi/ic_description_white_48dp.png                            |   0 
src/main/res/drawable-mdpi/ic_directions_black_24dp.png                             |   0 
src/main/res/drawable-mdpi/ic_directions_white_24dp.png                             |   0 
src/main/res/drawable-mdpi/ic_done_black_18dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_done_white_18dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_drafts_white_24dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_edit_black_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_edit_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_error_white_24dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_event_black_48dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_event_white_48dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_file_download_white_24dp.png                          |   0 
src/main/res/drawable-mdpi/ic_flip_camera_android_black_24dp.png                    |   0 
src/main/res/drawable-mdpi/ic_forward_white_24dp.png                                |   0 
src/main/res/drawable-mdpi/ic_gps_fixed_black_24dp.png                              |   0 
src/main/res/drawable-mdpi/ic_gps_fixed_white_24dp.png                              |   0 
src/main/res/drawable-mdpi/ic_gps_not_fixed_black_24dp.png                          |   0 
src/main/res/drawable-mdpi/ic_gps_not_fixed_white_24dp.png                          |   0 
src/main/res/drawable-mdpi/ic_group_add_white_24dp.png                              |   0 
src/main/res/drawable-mdpi/ic_group_white_24dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_headset_black_24dp.png                                |   0 
src/main/res/drawable-mdpi/ic_headset_black_48dp.png                                |   0 
src/main/res/drawable-mdpi/ic_headset_white_48dp.png                                |   0 
src/main/res/drawable-mdpi/ic_help_black_48dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_help_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_help_white_48dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_hourglass_empty_white_24dp.png                        |   0 
src/main/res/drawable-mdpi/ic_image_black_48dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_image_white_48dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_input_white_24dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_link_off_white_24dp.png                               |   0 
src/main/res/drawable-mdpi/ic_link_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_lock_black_18dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_lock_open_white_24dp.png                              |   0 
src/main/res/drawable-mdpi/ic_lock_white_18dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_lock_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_mic_black_24dp.png                                    |   0 
src/main/res/drawable-mdpi/ic_mic_black_48dp.png                                    |   0 
src/main/res/drawable-mdpi/ic_mic_off_black_24dp.png                                |   0 
src/main/res/drawable-mdpi/ic_mic_white_48dp.png                                    |   0 
src/main/res/drawable-mdpi/ic_mode_edit_black_18dp.png                              |   0 
src/main/res/drawable-mdpi/ic_mode_edit_white_18dp.png                              |   0 
src/main/res/drawable-mdpi/ic_new_releases_black_24dp.png                           |   0 
src/main/res/drawable-mdpi/ic_new_releases_white_24dp.png                           |   0 
src/main/res/drawable-mdpi/ic_no_results_background_black.png                       |   0 
src/main/res/drawable-mdpi/ic_no_results_background_white.png                       |   0 
src/main/res/drawable-mdpi/ic_notifications_black_24dp.png                          |   0 
src/main/res/drawable-mdpi/ic_notifications_none_black_24dp.png                     |   0 
src/main/res/drawable-mdpi/ic_notifications_none_white80.png                        |   0 
src/main/res/drawable-mdpi/ic_notifications_none_white_24dp.png                     |   0 
src/main/res/drawable-mdpi/ic_notifications_off_black_24dp.png                      |   0 
src/main/res/drawable-mdpi/ic_notifications_off_white80.png                         |   0 
src/main/res/drawable-mdpi/ic_notifications_off_white_24dp.png                      |   0 
src/main/res/drawable-mdpi/ic_notifications_paused_black_24dp.png                   |   0 
src/main/res/drawable-mdpi/ic_notifications_paused_white80.png                      |   0 
src/main/res/drawable-mdpi/ic_notifications_paused_white_24dp.png                   |   0 
src/main/res/drawable-mdpi/ic_notifications_white80.png                             |   0 
src/main/res/drawable-mdpi/ic_notifications_white_24dp.png                          |   0 
src/main/res/drawable-mdpi/ic_pause_black_36dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_pause_white_36dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_person_add_white_24dp.png                             |   0 
src/main/res/drawable-mdpi/ic_person_black_48dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_person_white_48dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_phone_in_talk_black_18dp.png                          |   0 
src/main/res/drawable-mdpi/ic_phone_in_talk_white_18dp.png                          |   0 
src/main/res/drawable-mdpi/ic_phone_in_talk_white_24dp.png                          |   0 
src/main/res/drawable-mdpi/ic_play_arrow_black_36dp.png                             |   0 
src/main/res/drawable-mdpi/ic_play_arrow_white_36dp.png                             |   0 
src/main/res/drawable-mdpi/ic_play_circle_filled_white_48dp.png                     |   0 
src/main/res/drawable-mdpi/ic_profile.png                                           |   0 
src/main/res/drawable-mdpi/ic_public_white_24dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_qr_code_scan_white_24dp.png                           |   0 
src/main/res/drawable-mdpi/ic_question_answer_white_24dp.png                        |   0 
src/main/res/drawable-mdpi/ic_refresh_black_24dp.png                                |   0 
src/main/res/drawable-mdpi/ic_refresh_white_24dp.png                                |   0 
src/main/res/drawable-mdpi/ic_replay_white_48dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_reply_white_24dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_room_black_48dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_room_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_room_white_48dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_save_black_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_save_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_search_background_black.png                           |   0 
src/main/res/drawable-mdpi/ic_search_background_white.png                           |   0 
src/main/res/drawable-mdpi/ic_search_white_24dp.png                                 |   0 
src/main/res/drawable-mdpi/ic_send_cancel_away.png                                  |   0 
src/main/res/drawable-mdpi/ic_send_cancel_dnd.png                                   |   0 
src/main/res/drawable-mdpi/ic_send_cancel_offline.png                               |   0 
src/main/res/drawable-mdpi/ic_send_cancel_offline_dark.png                          |   0 
src/main/res/drawable-mdpi/ic_send_cancel_offline_white.png                         |   0 
src/main/res/drawable-mdpi/ic_send_cancel_online.png                                |   0 
src/main/res/drawable-mdpi/ic_send_file_offline.png                                 |   0 
src/main/res/drawable-mdpi/ic_send_file_offline_white.png                           |   0 
src/main/res/drawable-mdpi/ic_send_location_away.png                                |   0 
src/main/res/drawable-mdpi/ic_send_location_dnd.png                                 |   0 
src/main/res/drawable-mdpi/ic_send_location_offline.png                             |   0 
src/main/res/drawable-mdpi/ic_send_location_offline_dark.png                        |   0 
src/main/res/drawable-mdpi/ic_send_location_offline_white.png                       |   0 
src/main/res/drawable-mdpi/ic_send_location_online.png                              |   0 
src/main/res/drawable-mdpi/ic_send_photo_away.png                                   |   0 
src/main/res/drawable-mdpi/ic_send_photo_dnd.png                                    |   0 
src/main/res/drawable-mdpi/ic_send_photo_offline.png                                |   0 
src/main/res/drawable-mdpi/ic_send_photo_offline_dark.png                           |   0 
src/main/res/drawable-mdpi/ic_send_photo_offline_white.png                          |   0 
src/main/res/drawable-mdpi/ic_send_photo_online.png                                 |   0 
src/main/res/drawable-mdpi/ic_send_picture_away.png                                 |   0 
src/main/res/drawable-mdpi/ic_send_picture_dnd.png                                  |   0 
src/main/res/drawable-mdpi/ic_send_picture_offline.png                              |   0 
src/main/res/drawable-mdpi/ic_send_picture_offline_dark.png                         |   0 
src/main/res/drawable-mdpi/ic_send_picture_offline_white.png                        |   0 
src/main/res/drawable-mdpi/ic_send_picture_online.png                               |   0 
src/main/res/drawable-mdpi/ic_send_text_away.png                                    |   0 
src/main/res/drawable-mdpi/ic_send_text_dnd.png                                     |   0 
src/main/res/drawable-mdpi/ic_send_text_offline.png                                 |   0 
src/main/res/drawable-mdpi/ic_send_text_offline_dark.png                            |   0 
src/main/res/drawable-mdpi/ic_send_text_offline_white.png                           |   0 
src/main/res/drawable-mdpi/ic_send_text_online.png                                  |   0 
src/main/res/drawable-mdpi/ic_send_videocam_away.png                                |   0 
src/main/res/drawable-mdpi/ic_send_videocam_dnd.png                                 |   0 
src/main/res/drawable-mdpi/ic_send_videocam_offline.png                             |   0 
src/main/res/drawable-mdpi/ic_send_videocam_offline_white.png                       |   0 
src/main/res/drawable-mdpi/ic_send_videocam_online.png                              |   0 
src/main/res/drawable-mdpi/ic_send_voice_away.png                                   |   0 
src/main/res/drawable-mdpi/ic_send_voice_dnd.png                                    |   0 
src/main/res/drawable-mdpi/ic_send_voice_offline.png                                |   0 
src/main/res/drawable-mdpi/ic_send_voice_offline_dark.png                           |   0 
src/main/res/drawable-mdpi/ic_send_voice_offline_white.png                          |   0 
src/main/res/drawable-mdpi/ic_send_voice_online.png                                 |   0 
src/main/res/drawable-mdpi/ic_settings_black_24dp.png                               |   0 
src/main/res/drawable-mdpi/ic_settings_white_24dp.png                               |   0 
src/main/res/drawable-mdpi/ic_share_white_24dp.png                                  |   0 
src/main/res/drawable-mdpi/ic_star_black_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_star_white_24dp.png                                   |   0 
src/main/res/drawable-mdpi/ic_stat_alert_warning.png                                |   0 
src/main/res/drawable-mdpi/ic_stat_communication_import_export.png                  |   0 
src/main/res/drawable-mdpi/ic_verified_fingerprint.png                              |   0 
src/main/res/drawable-mdpi/ic_verified_user_black_18dp.png                          |   0 
src/main/res/drawable-mdpi/ic_verified_user_white_18dp.png                          |   0 
src/main/res/drawable-mdpi/ic_videocam_black_24dp.png                               |   0 
src/main/res/drawable-mdpi/ic_videocam_off_black_24dp.png                           |   0 
src/main/res/drawable-mdpi/ic_videocam_white_24dp.png                               |   0 
src/main/res/drawable-mdpi/ic_voicemail_white_24dp.png                              |   0 
src/main/res/drawable-mdpi/ic_volume_off_black_24dp.png                             |   0 
src/main/res/drawable-mdpi/ic_volume_up_black_24dp.png                              |   0 
src/main/res/drawable-mdpi/ic_warning_white_24dp.png                                |   0 
src/main/res/drawable-mdpi/ic_warning_white_48dp.png                                |   0 
src/main/res/drawable-mdpi/ic_wear_reply.png                                        |   0 
src/main/res/drawable-mdpi/message_bubble_received.9.png                            |   0 
src/main/res/drawable-mdpi/message_bubble_received_dark.9.png                       |   0 
src/main/res/drawable-mdpi/message_bubble_received_grey.9.png                       |   0 
src/main/res/drawable-mdpi/message_bubble_received_warning.9.png                    |   0 
src/main/res/drawable-mdpi/message_bubble_received_white.9.png                      |   0 
src/main/res/drawable-mdpi/message_bubble_sent.9.png                                |   0 
src/main/res/drawable-mdpi/message_bubble_sent_grey.9.png                           |   0 
src/main/res/drawable-mdpi/play_gif_black.png                                       |   0 
src/main/res/drawable-mdpi/play_gif_white.png                                       |   0 
src/main/res/drawable-mdpi/play_video_black.png                                     |   0 
src/main/res/drawable-mdpi/play_video_white.png                                     |   0 
src/main/res/drawable-xhdpi/baseline_tour_black_48.png                              |   0 
src/main/res/drawable-xhdpi/baseline_tour_white_48.png                              |   0 
src/main/res/drawable-xhdpi/date_bubble_grey.9.png                                  |   0 
src/main/res/drawable-xhdpi/date_bubble_white.9.png                                 |   0 
src/main/res/drawable-xhdpi/ic_account_box_white_24dp.png                           |   0 
src/main/res/drawable-xhdpi/ic_action_reply.png                                     |   0 
src/main/res/drawable-xhdpi/ic_add_white_24dp.png                                   |   0 
src/main/res/drawable-xhdpi/ic_android_black_48dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_android_white_48dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_announcement_white_24dp.png                          |   0 
src/main/res/drawable-xhdpi/ic_archive_black_48dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_archive_white_24dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_archive_white_48dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_attach_camera.png                                    |   0 
src/main/res/drawable-xhdpi/ic_attach_camera_white.png                              |   0 
src/main/res/drawable-xhdpi/ic_attach_document.png                                  |   0 
src/main/res/drawable-xhdpi/ic_attach_document_white.png                            |   0 
src/main/res/drawable-xhdpi/ic_attach_file_white_24dp.png                           |   0 
src/main/res/drawable-xhdpi/ic_attach_location.png                                  |   0 
src/main/res/drawable-xhdpi/ic_attach_location_white.png                            |   0 
src/main/res/drawable-xhdpi/ic_attach_photo.png                                     |   0 
src/main/res/drawable-xhdpi/ic_attach_photo_white.png                               |   0 
src/main/res/drawable-xhdpi/ic_attach_record.png                                    |   0 
src/main/res/drawable-xhdpi/ic_attach_record_white.png                              |   0 
src/main/res/drawable-xhdpi/ic_attach_videocam.png                                  |   0 
src/main/res/drawable-xhdpi/ic_attach_videocam_white.png                            |   0 
src/main/res/drawable-xhdpi/ic_autorenew_white_24dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_backup_black_48dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_backup_white_48dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_block_white_24dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_bluetooth_audio_black_24dp.png                       |   0 
src/main/res/drawable-xhdpi/ic_book_black_48dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_book_white_48dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_call_black_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_call_end_white_48dp.png                              |   0 
src/main/res/drawable-xhdpi/ic_call_made_black_18dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_call_made_white_18dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_call_missed_black_18dp.png                           |   0 
src/main/res/drawable-xhdpi/ic_call_missed_outgoing_black_18dp.png                  |   0 
src/main/res/drawable-xhdpi/ic_call_missed_outgoing_white_18dp.png                  |   0 
src/main/res/drawable-xhdpi/ic_call_missed_white_18dp.png                           |   0 
src/main/res/drawable-xhdpi/ic_call_received_black_18dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_call_received_white_18dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_call_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_call_white_48dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_camera_alt_white_24dp.png                            |   0 
src/main/res/drawable-xhdpi/ic_cancel_black_24dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_cancel_white_24dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_chat_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_clear_white_48dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_cloud_download_white_24dp.png                        |   0 
src/main/res/drawable-xhdpi/ic_content_copy_white_24dp.png                          |   0 
src/main/res/drawable-xhdpi/ic_crop_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_delete_black_24dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_delete_white_24dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_description_black_48dp.png                           |   0 
src/main/res/drawable-xhdpi/ic_description_white_48dp.png                           |   0 
src/main/res/drawable-xhdpi/ic_directions_black_24dp.png                            |   0 
src/main/res/drawable-xhdpi/ic_directions_white_24dp.png                            |   0 
src/main/res/drawable-xhdpi/ic_done_black_18dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_done_white_18dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_drafts_white_24dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_edit_black_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_edit_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_error_white_24dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_event_black_48dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_event_white_48dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_file_download_white_24dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_flip_camera_android_black_24dp.png                   |   0 
src/main/res/drawable-xhdpi/ic_forward_white_24dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_gps_fixed_black_24dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_gps_fixed_white_24dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_gps_not_fixed_black_24dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_gps_not_fixed_white_24dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_group_add_white_24dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_group_white_24dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_headset_black_24dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_headset_black_48dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_headset_white_48dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_help_black_48dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_help_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_help_white_48dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_hourglass_empty_white_24dp.png                       |   0 
src/main/res/drawable-xhdpi/ic_image_black_48dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_image_white_48dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_input_white_24dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_link_off_white_24dp.png                              |   0 
src/main/res/drawable-xhdpi/ic_link_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_lock_black_18dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_lock_open_white_24dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_lock_white_18dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_lock_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_mic_black_24dp.png                                   |   0 
src/main/res/drawable-xhdpi/ic_mic_black_48dp.png                                   |   0 
src/main/res/drawable-xhdpi/ic_mic_off_black_24dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_mic_white_48dp.png                                   |   0 
src/main/res/drawable-xhdpi/ic_mode_edit_black_18dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_mode_edit_white_18dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_new_releases_black_24dp.png                          |   0 
src/main/res/drawable-xhdpi/ic_new_releases_white_24dp.png                          |   0 
src/main/res/drawable-xhdpi/ic_no_results_background_black.png                      |   0 
src/main/res/drawable-xhdpi/ic_no_results_background_white.png                      |   0 
src/main/res/drawable-xhdpi/ic_notifications_black_24dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_notifications_none_black_24dp.png                    |   0 
src/main/res/drawable-xhdpi/ic_notifications_none_white80.png                       |   0 
src/main/res/drawable-xhdpi/ic_notifications_none_white_24dp.png                    |   0 
src/main/res/drawable-xhdpi/ic_notifications_off_black_24dp.png                     |   0 
src/main/res/drawable-xhdpi/ic_notifications_off_white80.png                        |   0 
src/main/res/drawable-xhdpi/ic_notifications_off_white_24dp.png                     |   0 
src/main/res/drawable-xhdpi/ic_notifications_paused_black_24dp.png                  |   0 
src/main/res/drawable-xhdpi/ic_notifications_paused_white80.png                     |   0 
src/main/res/drawable-xhdpi/ic_notifications_paused_white_24dp.png                  |   0 
src/main/res/drawable-xhdpi/ic_notifications_white80.png                            |   0 
src/main/res/drawable-xhdpi/ic_notifications_white_24dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_pause_black_36dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_pause_white_36dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_person_add_white_24dp.png                            |   0 
src/main/res/drawable-xhdpi/ic_person_black_48dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_person_white_48dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_phone_in_talk_black_18dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_phone_in_talk_white_18dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_phone_in_talk_white_24dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_play_arrow_black_36dp.png                            |   0 
src/main/res/drawable-xhdpi/ic_play_arrow_white_36dp.png                            |   0 
src/main/res/drawable-xhdpi/ic_play_circle_filled_white_48dp.png                    |   0 
src/main/res/drawable-xhdpi/ic_profile.png                                          |   0 
src/main/res/drawable-xhdpi/ic_public_white_24dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_qr_code_scan_white_24dp.png                          |   0 
src/main/res/drawable-xhdpi/ic_question_answer_white_24dp.png                       |   0 
src/main/res/drawable-xhdpi/ic_refresh_black_24dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_refresh_white_24dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_replay_white_48dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_reply_white_24dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_room_black_48dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_room_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_room_white_48dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_save_black_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_save_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_search_background_black.png                          |   0 
src/main/res/drawable-xhdpi/ic_search_background_white.png                          |   0 
src/main/res/drawable-xhdpi/ic_search_white_24dp.png                                |   0 
src/main/res/drawable-xhdpi/ic_send_cancel_away.png                                 |   0 
src/main/res/drawable-xhdpi/ic_send_cancel_dnd.png                                  |   0 
src/main/res/drawable-xhdpi/ic_send_cancel_offline.png                              |   0 
src/main/res/drawable-xhdpi/ic_send_cancel_offline_dark.png                         |   0 
src/main/res/drawable-xhdpi/ic_send_cancel_offline_white.png                        |   0 
src/main/res/drawable-xhdpi/ic_send_cancel_online.png                               |   0 
src/main/res/drawable-xhdpi/ic_send_file_offline.png                                |   0 
src/main/res/drawable-xhdpi/ic_send_file_offline_white.png                          |   0 
src/main/res/drawable-xhdpi/ic_send_location_away.png                               |   0 
src/main/res/drawable-xhdpi/ic_send_location_dnd.png                                |   0 
src/main/res/drawable-xhdpi/ic_send_location_offline.png                            |   0 
src/main/res/drawable-xhdpi/ic_send_location_offline_dark.png                       |   0 
src/main/res/drawable-xhdpi/ic_send_location_offline_white.png                      |   0 
src/main/res/drawable-xhdpi/ic_send_location_online.png                             |   0 
src/main/res/drawable-xhdpi/ic_send_photo_away.png                                  |   0 
src/main/res/drawable-xhdpi/ic_send_photo_dnd.png                                   |   0 
src/main/res/drawable-xhdpi/ic_send_photo_offline.png                               |   0 
src/main/res/drawable-xhdpi/ic_send_photo_offline_dark.png                          |   0 
src/main/res/drawable-xhdpi/ic_send_photo_offline_white.png                         |   0 
src/main/res/drawable-xhdpi/ic_send_photo_online.png                                |   0 
src/main/res/drawable-xhdpi/ic_send_picture_away.png                                |   0 
src/main/res/drawable-xhdpi/ic_send_picture_dnd.png                                 |   0 
src/main/res/drawable-xhdpi/ic_send_picture_offline.png                             |   0 
src/main/res/drawable-xhdpi/ic_send_picture_offline_dark.png                        |   0 
src/main/res/drawable-xhdpi/ic_send_picture_offline_white.png                       |   0 
src/main/res/drawable-xhdpi/ic_send_picture_online.png                              |   0 
src/main/res/drawable-xhdpi/ic_send_text_away.png                                   |   0 
src/main/res/drawable-xhdpi/ic_send_text_dnd.png                                    |   0 
src/main/res/drawable-xhdpi/ic_send_text_offline.png                                |   0 
src/main/res/drawable-xhdpi/ic_send_text_offline_dark.png                           |   0 
src/main/res/drawable-xhdpi/ic_send_text_offline_white.png                          |   0 
src/main/res/drawable-xhdpi/ic_send_text_online.png                                 |   0 
src/main/res/drawable-xhdpi/ic_send_videocam_away.png                               |   0 
src/main/res/drawable-xhdpi/ic_send_videocam_dnd.png                                |   0 
src/main/res/drawable-xhdpi/ic_send_videocam_offline.png                            |   0 
src/main/res/drawable-xhdpi/ic_send_videocam_offline_white.png                      |   0 
src/main/res/drawable-xhdpi/ic_send_videocam_online.png                             |   0 
src/main/res/drawable-xhdpi/ic_send_voice_away.png                                  |   0 
src/main/res/drawable-xhdpi/ic_send_voice_dnd.png                                   |   0 
src/main/res/drawable-xhdpi/ic_send_voice_offline.png                               |   0 
src/main/res/drawable-xhdpi/ic_send_voice_offline_dark.png                          |   0 
src/main/res/drawable-xhdpi/ic_send_voice_offline_white.png                         |   0 
src/main/res/drawable-xhdpi/ic_send_voice_online.png                                |   0 
src/main/res/drawable-xhdpi/ic_settings_black_24dp.png                              |   0 
src/main/res/drawable-xhdpi/ic_settings_white_24dp.png                              |   0 
src/main/res/drawable-xhdpi/ic_share_white_24dp.png                                 |   0 
src/main/res/drawable-xhdpi/ic_star_black_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_star_white_24dp.png                                  |   0 
src/main/res/drawable-xhdpi/ic_stat_alert_warning.png                               |   0 
src/main/res/drawable-xhdpi/ic_stat_communication_import_export.png                 |   0 
src/main/res/drawable-xhdpi/ic_verified_fingerprint.png                             |   0 
src/main/res/drawable-xhdpi/ic_verified_user_black_18dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_verified_user_white_18dp.png                         |   0 
src/main/res/drawable-xhdpi/ic_videocam_black_24dp.png                              |   0 
src/main/res/drawable-xhdpi/ic_videocam_off_black_24dp.png                          |   0 
src/main/res/drawable-xhdpi/ic_videocam_white_24dp.png                              |   0 
src/main/res/drawable-xhdpi/ic_voicemail_white_24dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_volume_off_black_24dp.png                            |   0 
src/main/res/drawable-xhdpi/ic_volume_up_black_24dp.png                             |   0 
src/main/res/drawable-xhdpi/ic_warning_white_24dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_warning_white_48dp.png                               |   0 
src/main/res/drawable-xhdpi/ic_wear_reply.png                                       |   0 
src/main/res/drawable-xhdpi/message_bubble_received.9.png                           |   0 
src/main/res/drawable-xhdpi/message_bubble_received_dark.9.png                      |   0 
src/main/res/drawable-xhdpi/message_bubble_received_grey.9.png                      |   0 
src/main/res/drawable-xhdpi/message_bubble_received_warning.9.png                   |   0 
src/main/res/drawable-xhdpi/message_bubble_received_white.9.png                     |   0 
src/main/res/drawable-xhdpi/message_bubble_sent.9.png                               |   0 
src/main/res/drawable-xhdpi/message_bubble_sent_grey.9.png                          |   0 
src/main/res/drawable-xxhdpi/baseline_tour_black_48.png                             |   0 
src/main/res/drawable-xxhdpi/baseline_tour_white_48.png                             |   0 
src/main/res/drawable-xxhdpi/date_bubble_grey.9.png                                 |   0 
src/main/res/drawable-xxhdpi/date_bubble_white.9.png                                |   0 
src/main/res/drawable-xxhdpi/ic_account_box_white_24dp.png                          |   0 
src/main/res/drawable-xxhdpi/ic_action_reply.png                                    |   0 
src/main/res/drawable-xxhdpi/ic_add_white_24dp.png                                  |   0 
src/main/res/drawable-xxhdpi/ic_android_black_48dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_android_white_48dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_announcement_white_24dp.png                         |   0 
src/main/res/drawable-xxhdpi/ic_archive_black_48dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_archive_white_24dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_archive_white_48dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_attach_camera.png                                   |   0 
src/main/res/drawable-xxhdpi/ic_attach_camera_white.png                             |   0 
src/main/res/drawable-xxhdpi/ic_attach_document.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_attach_document_white.png                           |   0 
src/main/res/drawable-xxhdpi/ic_attach_file_white_24dp.png                          |   0 
src/main/res/drawable-xxhdpi/ic_attach_location.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_attach_location_white.png                           |   0 
src/main/res/drawable-xxhdpi/ic_attach_photo.png                                    |   0 
src/main/res/drawable-xxhdpi/ic_attach_photo_white.png                              |   0 
src/main/res/drawable-xxhdpi/ic_attach_record.png                                   |   0 
src/main/res/drawable-xxhdpi/ic_attach_record_white.png                             |   0 
src/main/res/drawable-xxhdpi/ic_attach_videocam.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_attach_videocam_white.png                           |   0 
src/main/res/drawable-xxhdpi/ic_autorenew_white_24dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_backup_black_48dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_backup_white_48dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_block_white_24dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_bluetooth_audio_black_24dp.png                      |   0 
src/main/res/drawable-xxhdpi/ic_book_black_48dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_book_white_48dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_call_black_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_call_end_white_48dp.png                             |   0 
src/main/res/drawable-xxhdpi/ic_call_made_black_18dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_call_made_white_18dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_call_missed_black_18dp.png                          |   0 
src/main/res/drawable-xxhdpi/ic_call_missed_outgoing_black_18dp.png                 |   0 
src/main/res/drawable-xxhdpi/ic_call_missed_outgoing_white_18dp.png                 |   0 
src/main/res/drawable-xxhdpi/ic_call_missed_white_18dp.png                          |   0 
src/main/res/drawable-xxhdpi/ic_call_received_black_18dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_call_received_white_18dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_call_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_call_white_48dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_camera_alt_white_24dp.png                           |   0 
src/main/res/drawable-xxhdpi/ic_cancel_black_24dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_cancel_white_24dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_chat_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_clear_white_48dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_cloud_download_white_24dp.png                       |   0 
src/main/res/drawable-xxhdpi/ic_content_copy_white_24dp.png                         |   0 
src/main/res/drawable-xxhdpi/ic_crop_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_delete_black_24dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_delete_white_24dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_description_black_48dp.png                          |   0 
src/main/res/drawable-xxhdpi/ic_description_white_48dp.png                          |   0 
src/main/res/drawable-xxhdpi/ic_directions_black_24dp.png                           |   0 
src/main/res/drawable-xxhdpi/ic_directions_white_24dp.png                           |   0 
src/main/res/drawable-xxhdpi/ic_done_black_18dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_done_white_18dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_drafts_white_24dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_edit_black_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_edit_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_error_white_24dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_event_black_48dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_event_white_48dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_file_download_white_24dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_flip_camera_android_black_24dp.png                  |   0 
src/main/res/drawable-xxhdpi/ic_forward_white_24dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_gps_fixed_black_24dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_gps_fixed_white_24dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_gps_not_fixed_black_24dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_gps_not_fixed_white_24dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_group_add_white_24dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_group_white_24dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_headset_black_24dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_headset_black_48dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_headset_white_48dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_help_black_48dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_help_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_help_white_48dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_hourglass_empty_white_24dp.png                      |   0 
src/main/res/drawable-xxhdpi/ic_image_black_48dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_image_white_48dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_input_white_24dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_link_off_white_24dp.png                             |   0 
src/main/res/drawable-xxhdpi/ic_link_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_lock_black_18dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_lock_open_white_24dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_lock_white_18dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_lock_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_mic_black_24dp.png                                  |   0 
src/main/res/drawable-xxhdpi/ic_mic_black_48dp.png                                  |   0 
src/main/res/drawable-xxhdpi/ic_mic_off_black_24dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_mic_white_48dp.png                                  |   0 
src/main/res/drawable-xxhdpi/ic_mode_edit_black_18dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_mode_edit_white_18dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_new_releases_black_24dp.png                         |   0 
src/main/res/drawable-xxhdpi/ic_new_releases_white_24dp.png                         |   0 
src/main/res/drawable-xxhdpi/ic_no_results_background_black.png                     |   0 
src/main/res/drawable-xxhdpi/ic_no_results_background_white.png                     |   0 
src/main/res/drawable-xxhdpi/ic_notifications_black_24dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_notifications_none_black_24dp.png                   |   0 
src/main/res/drawable-xxhdpi/ic_notifications_none_white80.png                      |   0 
src/main/res/drawable-xxhdpi/ic_notifications_none_white_24dp.png                   |   0 
src/main/res/drawable-xxhdpi/ic_notifications_off_black_24dp.png                    |   0 
src/main/res/drawable-xxhdpi/ic_notifications_off_white80.png                       |   0 
src/main/res/drawable-xxhdpi/ic_notifications_off_white_24dp.png                    |   0 
src/main/res/drawable-xxhdpi/ic_notifications_paused_black_24dp.png                 |   0 
src/main/res/drawable-xxhdpi/ic_notifications_paused_white80.png                    |   0 
src/main/res/drawable-xxhdpi/ic_notifications_paused_white_24dp.png                 |   0 
src/main/res/drawable-xxhdpi/ic_notifications_white80.png                           |   0 
src/main/res/drawable-xxhdpi/ic_notifications_white_24dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_pause_black_36dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_pause_white_36dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_person_add_white_24dp.png                           |   0 
src/main/res/drawable-xxhdpi/ic_person_black_48dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_person_white_48dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_phone_in_talk_black_18dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_phone_in_talk_white_18dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_phone_in_talk_white_24dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_play_arrow_black_36dp.png                           |   0 
src/main/res/drawable-xxhdpi/ic_play_arrow_white_36dp.png                           |   0 
src/main/res/drawable-xxhdpi/ic_play_circle_filled_white_48dp.png                   |   0 
src/main/res/drawable-xxhdpi/ic_profile.png                                         |   0 
src/main/res/drawable-xxhdpi/ic_public_white_24dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_qr_code_scan_white_24dp.png                         |   0 
src/main/res/drawable-xxhdpi/ic_question_answer_white_24dp.png                      |   0 
src/main/res/drawable-xxhdpi/ic_refresh_black_24dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_refresh_white_24dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_replay_white_48dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_reply_white_24dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_room_black_48dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_room_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_room_white_48dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_save_black_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_save_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_search_background_black.png                         |   0 
src/main/res/drawable-xxhdpi/ic_search_background_white.png                         |   0 
src/main/res/drawable-xxhdpi/ic_search_white_24dp.png                               |   0 
src/main/res/drawable-xxhdpi/ic_send_cancel_away.png                                |   0 
src/main/res/drawable-xxhdpi/ic_send_cancel_dnd.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_send_cancel_offline.png                             |   0 
src/main/res/drawable-xxhdpi/ic_send_cancel_offline_white.png                       |   0 
src/main/res/drawable-xxhdpi/ic_send_cancel_online.png                              |   0 
src/main/res/drawable-xxhdpi/ic_send_file_offline.png                               |   0 
src/main/res/drawable-xxhdpi/ic_send_file_offline_white.png                         |   0 
src/main/res/drawable-xxhdpi/ic_send_location_away.png                              |   0 
src/main/res/drawable-xxhdpi/ic_send_location_dnd.png                               |   0 
src/main/res/drawable-xxhdpi/ic_send_location_offline.png                           |   0 
src/main/res/drawable-xxhdpi/ic_send_location_offline_white.png                     |   0 
src/main/res/drawable-xxhdpi/ic_send_location_online.png                            |   0 
src/main/res/drawable-xxhdpi/ic_send_photo_away.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_send_photo_dnd.png                                  |   0 
src/main/res/drawable-xxhdpi/ic_send_photo_offline.png                              |   0 
src/main/res/drawable-xxhdpi/ic_send_photo_offline_white.png                        |   0 
src/main/res/drawable-xxhdpi/ic_send_photo_online.png                               |   0 
src/main/res/drawable-xxhdpi/ic_send_picture_away.png                               |   0 
src/main/res/drawable-xxhdpi/ic_send_picture_dnd.png                                |   0 
src/main/res/drawable-xxhdpi/ic_send_picture_offline.png                            |   0 
src/main/res/drawable-xxhdpi/ic_send_picture_offline_white.png                      |   0 
src/main/res/drawable-xxhdpi/ic_send_picture_online.png                             |   0 
src/main/res/drawable-xxhdpi/ic_send_text_away.png                                  |   0 
src/main/res/drawable-xxhdpi/ic_send_text_dnd.png                                   |   0 
src/main/res/drawable-xxhdpi/ic_send_text_offline.png                               |   0 
src/main/res/drawable-xxhdpi/ic_send_text_offline_white.png                         |   0 
src/main/res/drawable-xxhdpi/ic_send_text_online.png                                |   0 
src/main/res/drawable-xxhdpi/ic_send_videocam_away.png                              |   0 
src/main/res/drawable-xxhdpi/ic_send_videocam_dnd.png                               |   0 
src/main/res/drawable-xxhdpi/ic_send_videocam_offline.png                           |   0 
src/main/res/drawable-xxhdpi/ic_send_videocam_offline_white.png                     |   0 
src/main/res/drawable-xxhdpi/ic_send_videocam_online.png                            |   0 
src/main/res/drawable-xxhdpi/ic_send_voice_away.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_send_voice_dnd.png                                  |   0 
src/main/res/drawable-xxhdpi/ic_send_voice_offline.png                              |   0 
src/main/res/drawable-xxhdpi/ic_send_voice_offline_white.png                        |   0 
src/main/res/drawable-xxhdpi/ic_send_voice_online.png                               |   0 
src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png                             |   0 
src/main/res/drawable-xxhdpi/ic_settings_white_24dp.png                             |   0 
src/main/res/drawable-xxhdpi/ic_share_white_24dp.png                                |   0 
src/main/res/drawable-xxhdpi/ic_star_black_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_star_white_24dp.png                                 |   0 
src/main/res/drawable-xxhdpi/ic_stat_alert_warning.png                              |   0 
src/main/res/drawable-xxhdpi/ic_stat_communication_import_export.png                |   0 
src/main/res/drawable-xxhdpi/ic_verified_fingerprint.png                            |   0 
src/main/res/drawable-xxhdpi/ic_verified_user_black_18dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_verified_user_white_18dp.png                        |   0 
src/main/res/drawable-xxhdpi/ic_videocam_black_24dp.png                             |   0 
src/main/res/drawable-xxhdpi/ic_videocam_off_black_24dp.png                         |   0 
src/main/res/drawable-xxhdpi/ic_videocam_white_24dp.png                             |   0 
src/main/res/drawable-xxhdpi/ic_voicemail_white_24dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_volume_off_black_24dp.png                           |   0 
src/main/res/drawable-xxhdpi/ic_volume_up_black_24dp.png                            |   0 
src/main/res/drawable-xxhdpi/ic_warning_white_24dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_warning_white_48dp.png                              |   0 
src/main/res/drawable-xxhdpi/ic_wear_reply.png                                      |   0 
src/main/res/drawable-xxhdpi/message_bubble_received.9.png                          |   0 
src/main/res/drawable-xxhdpi/message_bubble_received_dark.9.png                     |   0 
src/main/res/drawable-xxhdpi/message_bubble_received_grey.9.png                     |   0 
src/main/res/drawable-xxhdpi/message_bubble_received_warning.9.png                  |   0 
src/main/res/drawable-xxhdpi/message_bubble_received_white.9.png                    |   0 
src/main/res/drawable-xxhdpi/message_bubble_sent.9.png                              |   0 
src/main/res/drawable-xxhdpi/message_bubble_sent_grey.9.png                         |   0 
src/main/res/drawable-xxxhdpi/baseline_tour_black_48.png                            |   0 
src/main/res/drawable-xxxhdpi/baseline_tour_white_48.png                            |   0 
src/main/res/drawable-xxxhdpi/date_bubble_grey.9.png                                |   0 
src/main/res/drawable-xxxhdpi/date_bubble_white.9.png                               |   0 
src/main/res/drawable-xxxhdpi/ic_account_box_white_24dp.png                         |   0 
src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png                                 |   0 
src/main/res/drawable-xxxhdpi/ic_android_black_48dp.png                             |   0 
src/main/res/drawable-xxxhdpi/ic_android_white_48dp.png                             |   0 
src/main/res/drawable-xxxhdpi/ic_announcement_white_24dp.png                        |   0 
src/main/res/drawable-xxxhdpi/ic_archive_black_48dp.png                             |   0 
src/main/res/drawable-xxxhdpi/ic_archive_white_24dp.png                             |   0 
src/main/res/drawable-xxxhdpi/ic_archive_white_48dp.png                             |   0 
src/main/res/drawable-xxxhdpi/ic_attach_camera.png                                  |   0 
src/main/res/drawable-xxxhdpi/ic_attach_camera_white.png                            |   0 
src/main/res/drawable-xxxhdpi/ic_attach_document.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_attach_document_white.png                          |   0 
src/main/res/drawable-xxxhdpi/ic_attach_file_white_24dp.png                         |   0 
src/main/res/drawable-xxxhdpi/ic_attach_location.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_attach_location_white.png                          |   0 
src/main/res/drawable-xxxhdpi/ic_attach_photo.png                                   |   0 
src/main/res/drawable-xxxhdpi/ic_attach_photo_white.png                             |   0 
src/main/res/drawable-xxxhdpi/ic_attach_record.png                                  |   0 
src/main/res/drawable-xxxhdpi/ic_attach_record_white.png                            |   0 
src/main/res/drawable-xxxhdpi/ic_attach_videocam.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_attach_videocam_white.png                          |   0 
src/main/res/drawable-xxxhdpi/ic_autorenew_white_24dp.png                           |   0 
src/main/res/drawable-xxxhdpi/ic_backup_black_48dp.png                              |   0 
src/main/res/drawable-xxxhdpi/ic_backup_white_48dp.png                              |   0 
src/main/res/drawable-xxxhdpi/ic_block_white_24dp.png                               |   0 
src/main/res/drawable-xxxhdpi/ic_bluetooth_audio_black_24dp.png                     |   0 
src/main/res/drawable-xxxhdpi/ic_book_black_48dp.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_book_white_48dp.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_call_black_24dp.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_call_end_white_48dp.png                            |   0 
src/main/res/drawable-xxxhdpi/ic_call_made_black_18dp.png                           |   0 
src/main/res/drawable-xxxhdpi/ic_call_made_white_18dp.png                           |   0 
src/main/res/drawable-xxxhdpi/ic_call_missed_black_18dp.png                         |   0 
src/main/res/drawable-xxxhdpi/ic_call_missed_outgoing_black_18dp.png                |   0 
src/main/res/drawable-xxxhdpi/ic_call_missed_outgoing_white_18dp.png                |   0 
src/main/res/drawable-xxxhdpi/ic_call_missed_white_18dp.png                         |   0 
src/main/res/drawable-xxxhdpi/ic_call_received_black_18dp.png                       |   0 
src/main/res/drawable-xxxhdpi/ic_call_received_white_18dp.png                       |   0 
src/main/res/drawable-xxxhdpi/ic_call_white_24dp.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_call_white_48dp.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_camera_alt_white_24dp.png                          |   0 
src/main/res/drawable-xxxhdpi/ic_cancel_black_24dp.png                              |   0 
src/main/res/drawable-xxxhdpi/ic_cancel_white_24dp.png                              |   0 
src/main/res/drawable-xxxhdpi/ic_chat_white_24dp.png                                |   0 
src/main/res/drawable-xxxhdpi/ic_clear_white_48dp.png                               |   0 
src/main/res/drawable-xxxhdpi/ic_cloud_download_white_24dp.png                      |   0 
src/main/res/drawable-xxxhdpi/ic_content_copy_white_24dp.png                        |   0 
src/main/res/drawable-xxxhdpi/ic_crop_white_24dp.png                                |   0 
1,000 files changed, 2,136 insertions(+), 2,379 deletions(-)

Detailed changes

build.gradle 🔗

@@ -74,7 +74,7 @@ dependencies {
     implementation 'org.hsluv:hsluv:0.2'
     implementation 'org.conscrypt:conscrypt-android:2.5.2'
     implementation 'me.drakeet.support:toastcompat:1.1.0'
-    implementation "com.leinardi.android:speed-dial:3.2.0"
+    implementation "com.leinardi.android:speed-dial:3.3.0"
 
     implementation "com.squareup.retrofit2:retrofit:2.9.0"
     implementation "com.squareup.retrofit2:converter-gson:2.9.0"

src/conversations/AndroidManifest.xml 🔗

@@ -5,6 +5,7 @@
         <activity
             android:name=".ui.ManageAccountActivity"
             android:label="@string/title_activity_manage_accounts"
+            android:theme="@style/Theme.Conversations3"
             android:launchMode="singleTask" />
         <activity
             android:name=".ui.WelcomeActivity"

src/conversations/java/eu/siacs/conversations/services/ImportBackupService.java 🔗

@@ -225,7 +225,7 @@ public class ImportBackupService extends Service {
         NotificationCompat.Builder mBuilder =
                 new NotificationCompat.Builder(getBaseContext(), "backup");
         mBuilder.setContentTitle(getString(R.string.restoring_backup))
-                .setSmallIcon(R.drawable.ic_unarchive_white_24dp)
+                .setSmallIcon(R.drawable.ic_unarchive_24dp)
                 .setProgress(max, progress, max == 1 && progress == 0);
         return mBuilder.build();
     }
@@ -415,7 +415,7 @@ public class ImportBackupService extends Service {
                                         ? PendingIntent.FLAG_IMMUTABLE
                                                 | PendingIntent.FLAG_UPDATE_CURRENT
                                         : PendingIntent.FLAG_UPDATE_CURRENT))
-                .setSmallIcon(R.drawable.ic_unarchive_white_24dp);
+                .setSmallIcon(R.drawable.ic_unarchive_24dp);
         notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
     }
 

src/conversations/java/eu/siacs/conversations/ui/EasyOnboardingInviteActivity.java 🔗

@@ -2,6 +2,7 @@ package eu.siacs.conversations.ui;
 
 import android.app.Activity;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.os.Bundle;
@@ -11,8 +12,10 @@ import android.view.MenuItem;
 import android.view.View;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.color.MaterialColors;
 import com.google.common.base.Strings;
 
 import eu.siacs.conversations.Config;
@@ -23,19 +26,20 @@ import eu.siacs.conversations.services.BarcodeProvider;
 import eu.siacs.conversations.utils.EasyOnboardingInvite;
 import eu.siacs.conversations.xmpp.Jid;
 
-public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOnboardingInvite.OnInviteRequested {
+public class EasyOnboardingInviteActivity extends XmppActivity
+        implements EasyOnboardingInvite.OnInviteRequested {
 
     private ActivityEasyInviteBinding binding;
 
     private EasyOnboardingInvite easyOnboardingInvite;
 
-
     @Override
     public void onCreate(final Bundle bundle) {
         super.onCreate(bundle);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_easy_invite);
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar(), true);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         this.binding.shareButton.setOnClickListener(v -> share());
         if (bundle != null && bundle.containsKey("invite")) {
             this.easyOnboardingInvite = bundle.getParcelable("invite");
@@ -65,11 +69,11 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
     }
 
     private void share() {
-        final String shareText = getString(
-                R.string.easy_invite_share_text,
-                easyOnboardingInvite.getDomain(),
-                easyOnboardingInvite.getShareableLink()
-        );
+        final String shareText =
+                getString(
+                        R.string.easy_invite_share_text,
+                        easyOnboardingInvite.getDomain(),
+                        easyOnboardingInvite.getShareableLink());
         final Intent sendIntent = new Intent();
         sendIntent.setAction(Intent.ACTION_SEND);
         sendIntent.putExtra(Intent.EXTRA_TEXT, shareText);
@@ -95,16 +99,47 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
     private void showInvite(final EasyOnboardingInvite invite) {
         this.binding.inProgress.setVisibility(View.GONE);
         this.binding.invite.setVisibility(View.VISIBLE);
-        this.binding.tapToShare.setText(getString(R.string.tap_share_button_send_invite, invite.getDomain()));
+        this.binding.tapToShare.setText(
+                getString(R.string.tap_share_button_send_invite, invite.getDomain()));
         final Point size = new Point();
         getWindowManager().getDefaultDisplay().getSize(size);
         final int width = Math.min(size.x, size.y);
-        final Bitmap bitmap = BarcodeProvider.create2dBarcodeBitmap(invite.getShareableLink(), width);
+        final boolean nightMode =
+                (this.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                        == Configuration.UI_MODE_NIGHT_YES;
+        final int black;
+        final int white;
+        if (nightMode) {
+            black =
+                    MaterialColors.getColor(
+                            this,
+                            com.google.android.material.R.attr.colorSurface,
+                            "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.colorSurface,
+                            "No surface color configured");
+        }
+        final Bitmap bitmap =
+                BarcodeProvider.create2dBarcodeBitmap(
+                        invite.getShareableLink(), width, black, white);
         binding.qrCode.setImageBitmap(bitmap);
     }
 
     @Override
-    public void onSaveInstanceState(Bundle bundle) {
+    public void onSaveInstanceState(@NonNull Bundle bundle) {
         super.onSaveInstanceState(bundle);
         if (easyOnboardingInvite != null) {
             bundle.putParcelable("invite", easyOnboardingInvite);
@@ -141,11 +176,12 @@ public class EasyOnboardingInviteActivity extends XmppActivity implements EasyOn
 
     @Override
     public void inviteRequestFailed(final String message) {
-        runOnUiThread(() -> {
-            if (!Strings.isNullOrEmpty(message)) {
-                Toast.makeText(this, message, Toast.LENGTH_LONG).show();
-            }
-            finish();
-        });
+        runOnUiThread(
+                () -> {
+                    if (!Strings.isNullOrEmpty(message)) {
+                        Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+                    }
+                    finish();
+                });
     }
 }

src/conversations/java/eu/siacs/conversations/ui/ImportBackupActivity.java 🔗

@@ -18,6 +18,7 @@ import androidx.appcompat.app.AlertDialog;
 import androidx.core.content.ContextCompat;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.snackbar.Snackbar;
 
 import java.io.IOException;
@@ -31,7 +32,6 @@ import eu.siacs.conversations.services.ImportBackupService;
 import eu.siacs.conversations.ui.adapter.BackupFileAdapter;
 import eu.siacs.conversations.ui.util.SettingsUtils;
 import eu.siacs.conversations.utils.BackupFileHeader;
-import eu.siacs.conversations.utils.ThemeHelper;
 
 public class ImportBackupActivity extends ActionBarActivity implements ServiceConnection, ImportBackupService.OnBackupFilesLoaded, BackupFileAdapter.OnItemClickedListener, ImportBackupService.OnBackupProcessed {
 
@@ -46,22 +46,15 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
 
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
-        this.mTheme = ThemeHelper.find(this);
-        setTheme(this.mTheme);
         super.onCreate(savedInstanceState);
         binding = DataBindingUtil.setContentView(this, R.layout.activity_import_backup);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         setLoadingState(savedInstanceState != null && savedInstanceState.getBoolean("loading_state", false));
         this.backupFileAdapter = new BackupFileAdapter();
         this.binding.list.setAdapter(this.backupFileAdapter);
         this.backupFileAdapter.setOnItemClickedListener(this);
     }
-    
-    @Override
-    protected void onResume(){
-        super.onResume();
-        SettingsUtils.applyScreenshotPreventionSetting(this);
-    }
 
     @Override
     public boolean onCreateOptionsMenu(final Menu menu) {
@@ -80,12 +73,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
     @Override
     public void onStart() {
         super.onStart();
-        final int theme = ThemeHelper.find(this);
-        if (this.mTheme != theme) {
-            recreate();
-        } else {
-            bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE);
-        }
+        bindService(new Intent(this, ImportBackupService.class), this, Context.BIND_AUTO_CREATE);
         final Intent intent = getIntent();
         if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction()) && !this.mLoadingState) {
             Uri uri = intent.getData();
@@ -146,7 +134,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
         final DialogEnterPasswordBinding enterPasswordBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.dialog_enter_password, null, false);
         Log.d(Config.LOGTAG, "attempting to import " + backupFile.getUri());
         enterPasswordBinding.explain.setText(getString(R.string.enter_password_to_restore, backupFile.getHeader().getJid().toString()));
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setView(enterPasswordBinding.getRoot());
         builder.setTitle(R.string.enter_password);
         builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
@@ -186,6 +174,7 @@ public class ImportBackupActivity extends ActionBarActivity implements ServiceCo
         binding.coordinator.setVisibility(loadingState ? View.GONE : View.VISIBLE);
         binding.inProgress.setVisibility(loadingState ? View.VISIBLE : View.GONE);
         setTitle(loadingState ? R.string.restoring_backup : R.string.restore_backup);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         configureActionBar(getSupportActionBar(), !loadingState);
         this.mLoadingState = loadingState;
         invalidateOptionsMenu();

src/conversations/java/eu/siacs/conversations/ui/MagicCreateActivity.java 🔗

@@ -10,45 +10,32 @@ import android.widget.Toast;
 
 import androidx.databinding.DataBindingUtil;
 
-import java.security.SecureRandom;
-
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.MagicCreateBinding;
+import eu.siacs.conversations.databinding.ActivityMagicCreateBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.utils.CryptoHelper;
 import eu.siacs.conversations.utils.InstallReferrerUtils;
 import eu.siacs.conversations.xmpp.Jid;
 
+import java.security.SecureRandom;
+
 public class MagicCreateActivity extends XmppActivity implements TextWatcher {
 
     public static final String EXTRA_DOMAIN = "domain";
     public static final String EXTRA_PRE_AUTH = "pre_auth";
     public static final String EXTRA_USERNAME = "username";
 
-    private MagicCreateBinding binding;
+    private ActivityMagicCreateBinding binding;
     private String domain;
     private String username;
     private String preAuth;
 
     @Override
-    protected void refreshUiReal() {
-
-    }
+    protected void refreshUiReal() {}
 
     @Override
-    void onBackendConnected() {
-
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        }
-    }
+    void onBackendConnected() {}
 
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
@@ -60,7 +47,8 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         }
         super.onCreate(savedInstanceState);
-        this.binding = DataBindingUtil.setContentView(this, R.layout.magic_create);
+        this.binding = DataBindingUtil.setContentView(this, R.layout.activity_magic_create);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(this.binding.toolbar);
         configureActionBar(getSupportActionBar(), this.domain == null);
         if (username != null && domain != null) {
@@ -72,51 +60,64 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
         } else if (domain != null) {
             binding.instructions.setText(getString(R.string.magic_create_text_on_x, domain));
         }
-        binding.createAccount.setOnClickListener(v -> {
-            try {
-                final String username = binding.username.getText().toString();
-                final Jid jid;
-                final boolean fixedUsername;
-                if (this.domain != null && this.username != null) {
-                    fixedUsername = true;
-                    jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain);
-                } else if (this.domain != null) {
-                    fixedUsername = false;
-                    jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
-                } else {
-                    fixedUsername = false;
-                    jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
-                }
-                if (!jid.getEscapedLocal().equals(jid.getLocal()) || (this.username == null && username.length() < 3)) {
-                    binding.username.setError(getString(R.string.invalid_username));
-                    binding.username.requestFocus();
-                } else {
-                    binding.username.setError(null);
-                    Account account = xmppConnectionService.findAccountByJid(jid);
-                    if (account == null) {
-                        account = new Account(jid, CryptoHelper.createPassword(new SecureRandom()));
-                        account.setOption(Account.OPTION_REGISTER, true);
-                        account.setOption(Account.OPTION_DISABLED, true);
-                        account.setOption(Account.OPTION_MAGIC_CREATE, true);
-                        account.setOption(Account.OPTION_FIXED_USERNAME, fixedUsername);
-                        if (this.preAuth != null) {
-                            account.setKey(Account.KEY_PRE_AUTH_REGISTRATION_TOKEN, this.preAuth);
+        binding.createAccount.setOnClickListener(
+                v -> {
+                    try {
+                        final String username = binding.username.getText().toString();
+                        final Jid jid;
+                        final boolean fixedUsername;
+                        if (this.domain != null && this.username != null) {
+                            fixedUsername = true;
+                            jid = Jid.ofLocalAndDomainEscaped(this.username, this.domain);
+                        } else if (this.domain != null) {
+                            fixedUsername = false;
+                            jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
+                        } else {
+                            fixedUsername = false;
+                            jid = Jid.ofLocalAndDomainEscaped(username, Config.MAGIC_CREATE_DOMAIN);
+                        }
+                        if (!jid.getEscapedLocal().equals(jid.getLocal())
+                                || (this.username == null && username.length() < 3)) {
+                            binding.usernameLayout.setError(getString(R.string.invalid_username));
+                            binding.username.requestFocus();
+                        } else {
+                            binding.usernameLayout.setError(null);
+                            Account account = xmppConnectionService.findAccountByJid(jid);
+                            if (account == null) {
+                                account =
+                                        new Account(
+                                                jid,
+                                                CryptoHelper.createPassword(new SecureRandom()));
+                                account.setOption(Account.OPTION_REGISTER, true);
+                                account.setOption(Account.OPTION_DISABLED, true);
+                                account.setOption(Account.OPTION_MAGIC_CREATE, true);
+                                account.setOption(Account.OPTION_FIXED_USERNAME, fixedUsername);
+                                if (this.preAuth != null) {
+                                    account.setKey(
+                                            Account.KEY_PRE_AUTH_REGISTRATION_TOKEN, this.preAuth);
+                                }
+                                xmppConnectionService.createAccount(account);
+                            }
+                            Intent intent =
+                                    new Intent(MagicCreateActivity.this, EditAccountActivity.class);
+                            intent.putExtra("jid", account.getJid().asBareJid().toString());
+                            intent.putExtra("init", true);
+                            intent.setFlags(
+                                    Intent.FLAG_ACTIVITY_NEW_TASK
+                                            | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                            Toast.makeText(
+                                            MagicCreateActivity.this,
+                                            R.string.secure_password_generated,
+                                            Toast.LENGTH_SHORT)
+                                    .show();
+                            StartConversationActivity.addInviteUri(intent, getIntent());
+                            startActivity(intent);
                         }
-                        xmppConnectionService.createAccount(account);
+                    } catch (final IllegalArgumentException e) {
+                        binding.usernameLayout.setError(getString(R.string.invalid_username));
+                        binding.username.requestFocus();
                     }
-                    Intent intent = new Intent(MagicCreateActivity.this, EditAccountActivity.class);
-                    intent.putExtra("jid", account.getJid().asBareJid().toString());
-                    intent.putExtra("init", true);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-                    Toast.makeText(MagicCreateActivity.this, R.string.secure_password_generated, Toast.LENGTH_SHORT).show();
-                    StartConversationActivity.addInviteUri(intent, getIntent());
-                    startActivity(intent);
-                }
-            } catch (IllegalArgumentException e) {
-                binding.username.setError(getString(R.string.invalid_username));
-                binding.username.requestFocus();
-            }
-        });
+                });
         binding.username.addTextChangedListener(this);
     }
 
@@ -127,14 +128,10 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
     }
 
     @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(final Editable s) {
@@ -153,8 +150,10 @@ public class MagicCreateActivity extends XmppActivity implements TextWatcher {
                 } else {
                     jid = Jid.ofLocalAndDomainEscaped(username, this.domain);
                 }
-                binding.fullJid.setText(getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
-            } catch (IllegalArgumentException e) {
+                binding.fullJid.setText(
+                        getString(R.string.your_full_jid_will_be, jid.toEscapedString()));
+                binding.usernameLayout.setError(null);
+            } catch (final IllegalArgumentException e) {
                 binding.fullJid.setVisibility(View.INVISIBLE);
             }
         }

src/conversations/java/eu/siacs/conversations/ui/ManageAccountActivity.java 🔗

@@ -1,10 +1,14 @@
 package eu.siacs.conversations.ui;
 
+import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
+import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
+
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.os.Bundle;
 import android.security.KeyChain;
 import android.security.KeyChainAliasCallback;
+import android.util.Log;
 import android.util.Pair;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -12,23 +16,17 @@ import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.ListView;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.ActionBar;
-import androidx.appcompat.app.AlertDialog;
+import androidx.databinding.DataBindingUtil;
 
-import org.openintents.openpgp.util.OpenPgpApi;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
+import com.google.common.base.Strings;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityManageAccountsBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
@@ -37,10 +35,17 @@ import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
 import eu.siacs.conversations.xmpp.Jid;
 import eu.siacs.conversations.xmpp.XmppConnection;
 
-import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
-import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
+import org.openintents.openpgp.util.OpenPgpApi;
 
-public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated, AccountAdapter.OnTglAccountState {
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class ManageAccountActivity extends XmppActivity
+        implements OnAccountUpdate,
+                KeyChainAliasCallback,
+                XmppConnectionService.OnAccountCreated,
+                AccountAdapter.OnTglAccountState {
 
     private final String STATE_SELECTED_ACCOUNT = "selected_account";
 
@@ -50,7 +55,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
     protected Jid selectedAccountJid = null;
 
     protected final List<Account> accountList = new ArrayList<>();
-    protected ListView accountListView;
     protected AccountAdapter mAccountAdapter;
     protected AtomicBoolean mInvokedAddAccount = new AtomicBoolean(false);
 
@@ -67,7 +71,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
             accountList.clear();
             accountList.addAll(xmppConnectionService.getAccounts());
         }
-        ActionBar actionBar = getSupportActionBar();
+        final ActionBar actionBar = getSupportActionBar();
         if (actionBar != null) {
             actionBar.setHomeButtonEnabled(this.accountList.size() > 0);
             actionBar.setDisplayHomeAsUpEnabled(this.accountList.size() > 0);
@@ -81,8 +85,11 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 
         super.onCreate(savedInstanceState);
 
-        setContentView(R.layout.activity_manage_accounts);
-        setSupportActionBar(findViewById(R.id.toolbar));
+        ActivityManageAccountsBinding binding =
+                DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts);
+
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+        setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
         if (savedInstanceState != null) {
             String jid = savedInstanceState.getString(STATE_SELECTED_ACCOUNT);
@@ -95,26 +102,19 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
             }
         }
 
-        accountListView = findViewById(R.id.account_list);
         this.mAccountAdapter = new AccountAdapter(this, accountList);
-        accountListView.setAdapter(this.mAccountAdapter);
-        accountListView.setOnItemClickListener((arg0, view, position, arg3) -> switchToAccount(accountList.get(position)));
-        registerForContextMenu(accountListView);
+        binding.accountList.setAdapter(this.mAccountAdapter);
+        binding.accountList.setOnItemClickListener(
+                (arg0, view, position, arg3) -> switchToAccount(accountList.get(position)));
+        registerForContextMenu(binding.accountList);
     }
 
-    @Override
-    protected void onStart() {
-        super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        }
-    }
 
     @Override
-    public void onSaveInstanceState(final Bundle savedInstanceState) {
+    public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
         if (selectedAccount != null) {
-            savedInstanceState.putString(STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toEscapedString());
+            savedInstanceState.putString(
+                    STATE_SELECTED_ACCOUNT, selectedAccount.getJid().asBareJid().toEscapedString());
         }
         super.onSaveInstanceState(savedInstanceState);
     }
@@ -122,8 +122,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
     @Override
     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
         super.onCreateContextMenu(menu, v, menuInfo);
-        ManageAccountActivity.this.getMenuInflater().inflate(
-                R.menu.manageaccounts_context, menu);
+        ManageAccountActivity.this.getMenuInflater().inflate(R.menu.manageaccounts_context, menu);
         AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo;
         this.selectedAccount = accountList.get(acmi.position);
         if (this.selectedAccount.isEnabled()) {
@@ -144,9 +143,10 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
         }
         refreshUiReal();
         if (this.mPostponedActivityResult != null) {
-            this.onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
+            this.onActivityResult(
+                    mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second);
         }
-        if (Config.X509_VERIFICATION && this.accountList.size() == 0) {
+        if (Config.X509_VERIFICATION && this.accountList.isEmpty()) {
             if (mInvokedAddAccount.compareAndSet(false, true)) {
                 addAccountFromKey();
             }
@@ -233,9 +233,9 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
         return super.onOptionsItemSelected(item);
     }
 
-
     @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+    public void onRequestPermissionsResult(
+            int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         if (grantResults.length > 0) {
             if (allGranted(grantResults)) {
@@ -258,13 +258,14 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
     @Override
     public boolean onNavigateUp() {
         if (xmppConnectionService.getConversations().size() == 0) {
-            Intent contactsIntent = new Intent(this,
-                    StartConversationActivity.class);
+            Intent contactsIntent = new Intent(this, StartConversationActivity.class);
             contactsIntent.setFlags(
                     // if activity exists in stack, pop the stack and go back to it
-                    Intent.FLAG_ACTIVITY_CLEAR_TOP |
+                    Intent.FLAG_ACTIVITY_CLEAR_TOP
+                            |
                             // otherwise, make a new task for it
-                            Intent.FLAG_ACTIVITY_NEW_TASK |
+                            Intent.FLAG_ACTIVITY_NEW_TASK
+                            |
                             // don't use the new activity animation; finish
                             // animation runs instead
                             Intent.FLAG_ACTIVITY_NO_ANIMATION);
@@ -286,16 +287,17 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
     }
 
     private void addAccountFromKey() {
+        Log.d(Config.LOGTAG, "add account from key");
         try {
             KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
-        } catch (ActivityNotFoundException e) {
-            Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG).show();
+        } catch (final ActivityNotFoundException e) {
+            Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG)
+                    .show();
         }
     }
 
     private void publishAvatar(Account account) {
-        Intent intent = new Intent(getApplicationContext(),
-                PublishProfilePictureActivity.class);
+        Intent intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
         intent.putExtra(EXTRA_ACCOUNT, account.getJid().asBareJid().toEscapedString());
         startActivity(intent);
     }
@@ -377,7 +379,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
         }
     }
 
-
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
@@ -385,7 +386,8 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
             if (xmppConnectionServiceBound) {
                 if (requestCode == REQUEST_CHOOSE_PGP_ID) {
                     if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) {
-                        selectedAccount.setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID));
+                        selectedAccount.setPgpSignId(
+                                data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID));
                         announcePgp(selectedAccount, null, null, onOpenPGPKeyPublished);
                     } else {
                         choosePgpSignId(selectedAccount);
@@ -402,9 +404,17 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 
     @Override
     public void alias(final String alias) {
-        if (alias != null) {
-            xmppConnectionService.createAccountFromKey(alias, this);
-        }
+        if (Strings.isNullOrEmpty(alias)) {
+            runOnUiThread(
+                    () ->
+                            Toast.makeText(
+                                            this,
+                                            R.string.no_certificate_selected,
+                                            Toast.LENGTH_LONG)
+                                    .show());
+            return;
+        }
+        xmppConnectionService.createAccountFromKey(alias, this);
     }
 
     @Override
@@ -417,6 +427,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
 
     @Override
     public void informUser(final int r) {
-        runOnUiThread(() -> Toast.makeText(ManageAccountActivity.this, r, Toast.LENGTH_LONG).show());
+        runOnUiThread(
+                () -> Toast.makeText(ManageAccountActivity.this, r, Toast.LENGTH_LONG).show());
     }
 }

src/conversations/java/eu/siacs/conversations/ui/PickServerActivity.java 🔗

@@ -26,15 +26,6 @@ public class PickServerActivity extends XmppActivity {
 
     }
 
-    @Override
-    public void onStart() {
-        super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        }
-    }
-
 
     @Override
     public boolean onOptionsItemSelected(final MenuItem item) {
@@ -53,7 +44,8 @@ public class PickServerActivity extends XmppActivity {
     }
 
     @Override
-    public void onNewIntent(Intent intent) {
+    public void onNewIntent(final Intent intent) {
+        super.onNewIntent(intent);
         if (intent != null) {
             setIntent(intent);
         }
@@ -66,6 +58,7 @@ public class PickServerActivity extends XmppActivity {
         }
         super.onCreate(savedInstanceState);
         ActivityPickServerBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_pick_server);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
         binding.useCim.setOnClickListener(v -> {
@@ -81,7 +74,7 @@ public class PickServerActivity extends XmppActivity {
             if (accounts.size() == 1) {
                 intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
                 intent.putExtra("init", true);
-            } else if (accounts.size() >= 1) {
+            } else if (!accounts.isEmpty()) {
                 intent = new Intent(this, ManageAccountActivity.class);
             }
             addInviteUri(intent);

src/conversations/java/eu/siacs/conversations/ui/ShareViaAccountActivity.java 🔗

@@ -56,15 +56,6 @@ public class ShareViaAccountActivity extends XmppActivity {
         });
     }
 
-    @Override
-    protected void onStart() {
-        super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        }
-    }
-
     @Override
     void onBackendConnected() {
         final int numAccounts = xmppConnectionService.getAccounts().size();

src/conversations/java/eu/siacs/conversations/ui/WelcomeActivity.java 🔗

@@ -34,7 +34,10 @@ import eu.siacs.conversations.xmpp.Jid;
 import static eu.siacs.conversations.utils.PermissionUtils.allGranted;
 import static eu.siacs.conversations.utils.PermissionUtils.writeGranted;
 
-public class WelcomeActivity extends XmppActivity implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback {
+import com.google.common.base.Strings;
+
+public class WelcomeActivity extends XmppActivity
+        implements XmppConnectionService.OnAccountCreated, KeyChainAliasCallback {
 
     private static final int REQUEST_IMPORT_BACKUP = 0x63fb;
 
@@ -66,7 +69,8 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
         final Intent intent;
         if (xmppUri.isAction(XmppUri.ACTION_REGISTER)) {
             intent = SignupUtils.getTokenRegistrationIntent(this, jid, preAuth);
-        } else if (xmppUri.isAction(XmppUri.ACTION_ROSTER) && "y".equals(xmppUri.getParameter(XmppUri.PARAMETER_IBR))) {
+        } else if (xmppUri.isAction(XmppUri.ACTION_ROSTER)
+                && "y".equals(xmppUri.getParameter(XmppUri.PARAMETER_IBR))) {
             intent = SignupUtils.getTokenRegistrationIntent(this, jid.getDomain(), preAuth);
             intent.putExtra(StartConversationActivity.EXTRA_INVITE_URI, xmppUri.toString());
         } else {
@@ -81,22 +85,14 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
     }
 
     @Override
-    protected void refreshUiReal() {
-
-    }
+    protected void refreshUiReal() {}
 
     @Override
-    void onBackendConnected() {
-
-    }
+    void onBackendConnected() {}
 
     @Override
     public void onStart() {
         super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        }
         new InstallReferrerUtils(this);
     }
 
@@ -119,42 +115,44 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         }
         super.onCreate(savedInstanceState);
-        ActivityWelcomeBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_welcome);
+        ActivityWelcomeBinding binding =
+                DataBindingUtil.setContentView(this, R.layout.activity_welcome);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar(), false);
-        binding.registerNewAccount.setOnClickListener(v -> {
-            final Intent intent = new Intent(this, PickServerActivity.class);
-            addInviteUri(intent);
-            startActivity(intent);
-        });
-        binding.useExisting.setOnClickListener(v -> {
-            final List<Account> accounts = xmppConnectionService.getAccounts();
-            Intent intent = new Intent(WelcomeActivity.this, EditAccountActivity.class);
-            intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false);
-            if (accounts.size() == 1) {
-                intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
-                intent.putExtra("init", true);
-            } else if (accounts.size() >= 1) {
-                intent = new Intent(WelcomeActivity.this, ManageAccountActivity.class);
-            }
-            addInviteUri(intent);
-            startActivity(intent);
-        });
-
+        setTitle(null);
+        binding.registerNewAccount.setOnClickListener(
+                v -> {
+                    final Intent intent = new Intent(this, PickServerActivity.class);
+                    addInviteUri(intent);
+                    startActivity(intent);
+                });
+        binding.useExisting.setOnClickListener(
+                v -> {
+                    final List<Account> accounts = xmppConnectionService.getAccounts();
+                    Intent intent = new Intent(this, EditAccountActivity.class);
+                    intent.putExtra(EditAccountActivity.EXTRA_FORCE_REGISTER, false);
+                    if (accounts.size() == 1) {
+                        intent.putExtra("jid", accounts.get(0).getJid().asBareJid().toString());
+                        intent.putExtra("init", true);
+                    } else if (!accounts.isEmpty()) {
+                        intent = new Intent(this, ManageAccountActivity.class);
+                    }
+                    addInviteUri(intent);
+                    startActivity(intent);
+                });
     }
 
     @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
+    public boolean onCreateOptionsMenu(final Menu menu) {
         getMenuInflater().inflate(R.menu.welcome_menu, menu);
         final MenuItem scan = menu.findItem(R.id.action_scan_qr_code);
         scan.setVisible(Compatibility.hasFeatureCamera(this));
         return super.onCreateOptionsMenu(menu);
     }
 
-
-
     @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
+    public boolean onOptionsItemSelected(final MenuItem item) {
         switch (item.getItemId()) {
             case R.id.action_import_backup:
                 if (hasStoragePermission(REQUEST_IMPORT_BACKUP)) {
@@ -174,16 +172,25 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
     private void addAccountFromKey() {
         try {
             KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null);
-        } catch (ActivityNotFoundException e) {
-            Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG).show();
+        } catch (final ActivityNotFoundException e) {
+            Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG)
+                    .show();
         }
     }
 
     @Override
     public void alias(final String alias) {
-        if (alias != null) {
-            xmppConnectionService.createAccountFromKey(alias, this);
+        if (Strings.isNullOrEmpty(alias)) {
+            runOnUiThread(
+                    () ->
+                            Toast.makeText(
+                                            this,
+                                            R.string.no_certificate_selected,
+                                            Toast.LENGTH_LONG)
+                                    .show());
+            return;
         }
+        xmppConnectionService.createAccountFromKey(alias, this);
     }
 
     @Override
@@ -201,7 +208,8 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
     }
 
     @Override
-    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+    public void onRequestPermissionsResult(
+            int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         UriHandlerActivity.onRequestPermissionResult(this, requestCode, grantResults);
         if (grantResults.length > 0) {
@@ -211,7 +219,8 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
                         startActivity(new Intent(this, ImportBackupActivity.class));
                         break;
                 }
-            } else if (Arrays.asList(permissions).contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+            } else if (Arrays.asList(permissions)
+                    .contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                 Toast.makeText(this, R.string.no_storage_permission, Toast.LENGTH_SHORT).show();
             }
         }
@@ -232,5 +241,4 @@ public class WelcomeActivity extends XmppActivity implements XmppConnectionServi
             to.putExtra(StartConversationActivity.EXTRA_INVITE_URI, this.inviteUri.toString());
         }
     }
-
 }

src/conversations/java/eu/siacs/conversations/ui/adapter/BackupFileAdapter.java 🔗

@@ -22,7 +22,7 @@ import java.util.List;
 import java.util.concurrent.RejectedExecutionException;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.AccountRowBinding;
+import eu.siacs.conversations.databinding.ItemAccountBinding;
 import eu.siacs.conversations.services.AvatarService;
 import eu.siacs.conversations.services.ImportBackupService;
 import eu.siacs.conversations.utils.BackupFileHeader;
@@ -39,7 +39,7 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
     @NonNull
     @Override
     public BackupFileViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
-        return new BackupFileViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.account_row, viewGroup, false));
+        return new BackupFileViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_account, viewGroup, false));
     }
 
     @Override
@@ -73,9 +73,9 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
     }
 
     static class BackupFileViewHolder extends RecyclerView.ViewHolder {
-        private final AccountRowBinding binding;
+        private final ItemAccountBinding binding;
 
-        BackupFileViewHolder(AccountRowBinding binding) {
+        BackupFileViewHolder(ItemAccountBinding binding) {
             super(binding.getRoot());
             this.binding = binding;
         }
@@ -91,7 +91,7 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
         private Jid jid  = null;
         private final int size;
 
-        BitmapWorkerTask(ImageView imageView) {
+        BitmapWorkerTask(final ImageView imageView) {
             imageViewReference = new WeakReference<>(imageView);
             DisplayMetrics metrics = imageView.getContext().getResources().getDisplayMetrics();
 		this.size = ((int) (48 * metrics.density));
@@ -146,8 +146,7 @@ public class BackupFileAdapter extends RecyclerView.Adapter<BackupFileAdapter.Ba
     private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
         if (imageView != null) {
             final Drawable drawable = imageView.getDrawable();
-            if (drawable instanceof AsyncDrawable) {
-                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+            if (drawable instanceof AsyncDrawable asyncDrawable) {
                 return asyncDrawable.getBitmapWorkerTask();
             }
         }

src/conversations/res/layout/activity_easy_invite.xml 🔗

@@ -1,17 +1,23 @@
 <?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
 
 
     <LinearLayout
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
-        android:background="?attr/color_background_primary"
         android:orientation="vertical">
 
-        <include
-            android:id="@+id/toolbar"
-            layout="@layout/toolbar" />
+        <com.google.android.material.appbar.AppBarLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <com.google.android.material.appbar.MaterialToolbar
+                android:id="@+id/toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:minHeight="?attr/actionBarSize" />
+
+        </com.google.android.material.appbar.AppBarLayout>
 
         <LinearLayout
             android:id="@+id/in_progress"
@@ -41,7 +47,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:text="@string/tap_share_button_send_invite"
-                android:textAppearance="@style/TextAppearance.Conversations.Body1" />
+                android:textAppearance="?textAppearanceBodyMedium" />
 
             <TextView
                 android:id="@+id/scan_the_code"
@@ -50,7 +56,7 @@
                 android:layout_below="@+id/tap_to_share"
                 android:layout_marginTop="24sp"
                 android:text="@string/if_contact_is_nearby_use_qr"
-                android:textAppearance="@style/TextAppearance.Conversations.Body1" />
+                android:textAppearance="?textAppearanceBodyMedium" />
 
             <ImageView
                 android:id="@+id/qr_code"
@@ -59,23 +65,19 @@
                 android:layout_above="@+id/share_button"
                 android:layout_below="@id/scan_the_code"
                 android:layout_alignParentStart="true"
-                android:layout_alignParentRight="true"
+                android:layout_alignParentEnd="true"
                 android:layout_centerHorizontal="true"
                 android:layout_margin="24sp"
                 android:scaleType="fitCenter" />
 
             <Button
                 android:id="@+id/share_button"
-                style="@style/Widget.Conversations.Button.Borderless"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_alignParentBottom="true"
-                android:minWidth="0dp"
-                android:paddingLeft="16dp"
-                android:paddingRight="16dp"
-                android:text="@string/share"
                 android:layout_centerHorizontal="true"
-                android:textColor="?attr/colorAccent" />
+                android:layout_marginHorizontal="16dp"
+                android:text="@string/share" />
 
         </RelativeLayout>
 

src/conversations/res/layout/activity_import_backup.xml 🔗

@@ -2,22 +2,30 @@
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
-
     <LinearLayout
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
-        android:background="?attr/color_background_primary"
         android:orientation="vertical">
 
-        <include
-            android:id="@+id/toolbar"
-            layout="@layout/toolbar" />
+        <com.google.android.material.appbar.AppBarLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <com.google.android.material.appbar.MaterialToolbar
+                android:id="@+id/toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:minHeight="?attr/actionBarSize" />
+
+        </com.google.android.material.appbar.AppBarLayout>
+
         <LinearLayout
-            android:visibility="gone"
             android:id="@+id/in_progress"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:gravity="center">
+            android:gravity="center"
+            android:visibility="gone">
+
             <ProgressBar
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
@@ -25,18 +33,15 @@
         </LinearLayout>
 
 
-
         <androidx.coordinatorlayout.widget.CoordinatorLayout
             android:id="@+id/coordinator"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="?attr/color_background_primary">
+            android:layout_height="match_parent">
 
             <androidx.recyclerview.widget.RecyclerView
                 android:id="@+id/list"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:background="?attr/color_background_primary"
                 android:orientation="vertical"
                 app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
         </androidx.coordinatorlayout.widget.CoordinatorLayout>

src/conversations/res/layout/magic_create.xml → src/conversations/res/layout/activity_magic_create.xml 🔗

@@ -7,7 +7,18 @@
         android:layout_height="match_parent"
         android:orientation="vertical">
 
-        <include layout="@layout/toolbar" android:id="@+id/toolbar"/>
+        <com.google.android.material.appbar.AppBarLayout
+            android:id="@+id/app_bar_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <com.google.android.material.appbar.MaterialToolbar
+                android:id="@+id/toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:minHeight="?attr/actionBarSize" />
+
+        </com.google.android.material.appbar.AppBarLayout>
 
         <ScrollView
             android:layout_width="match_parent"
@@ -16,15 +27,13 @@
 
             <RelativeLayout
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:background="?attr/color_background_primary">
+                android:layout_height="wrap_content">
 
                 <LinearLayout
                     android:id="@+id/linearLayout"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_alignParentStart="true"
-                    android:layout_alignParentLeft="true"
                     android:layout_alignParentBottom="true"
                     android:minHeight="256dp"
                     android:orientation="vertical"
@@ -42,50 +51,53 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/pick_your_username"
-                        android:textAppearance="@style/TextAppearance.Conversations.Title" />
+                        android:textAppearance="?textAppearanceTitleLarge" />
 
                     <TextView
                         android:id="@+id/instructions"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_marginTop="8dp"
+                        android:layout_marginVertical="8dp"
                         android:text="@string/magic_create_text"
-                        android:textAppearance="@style/TextAppearance.Conversations.Body1" />
+                        android:textAppearance="?textAppearanceBodyMedium" />
 
-                    <EditText
-                        android:id="@+id/username"
+                    <com.google.android.material.textfield.TextInputLayout
+                        android:id="@+id/username_layout"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:layout_gravity="center_horizontal"
-                        android:hint="@string/username_hint"
-                        android:textColor="?attr/edit_text_color"
-                        android:inputType="textNoSuggestions" />
+                        android:hint="@string/username_hint">
+
+                        <com.google.android.material.textfield.TextInputEditText
+                            android:id="@+id/username"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center_horizontal"
+                            android:inputType="textNoSuggestions" />
+                    </com.google.android.material.textfield.TextInputLayout>
 
                     <TextView
                         android:id="@+id/full_jid"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_marginTop="8dp"
+                        android:layout_marginVertical="8dp"
                         android:text="@string/your_full_jid_will_be"
-                        android:textAppearance="@style/TextAppearance.Conversations.Caption"
+                        android:textAppearance="?textAppearanceLabelSmall"
                         android:visibility="invisible" />
 
                     <Button
                         android:id="@+id/create_account"
-                        style="@style/Widget.Conversations.Button.Borderless"
+                        style="@style/Widget.Material3.Button.TonalButton"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_gravity="right"
-                        android:text="@string/next"
-                        android:textColor="?colorAccent" />
+                        android:layout_gravity="end"
+                        android:text="@string/next" />
                 </LinearLayout>
 
                 <RelativeLayout
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
                     android:layout_above="@+id/linearLayout"
-                    android:layout_alignParentStart="true"
-                    android:layout_alignParentLeft="true">
+                    android:layout_alignParentStart="true">
 
                     <ImageView
                         android:layout_width="wrap_content"

src/conversations/res/layout/activity_pick_server.xml 🔗

@@ -7,7 +7,17 @@
         android:layout_height="match_parent"
         android:orientation="vertical">
 
-        <include android:id="@+id/toolbar" layout="@layout/toolbar" />
+        <com.google.android.material.appbar.AppBarLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <com.google.android.material.appbar.MaterialToolbar
+                android:id="@+id/toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:minHeight="?attr/actionBarSize" />
+
+        </com.google.android.material.appbar.AppBarLayout>
 
         <ScrollView
             android:layout_width="match_parent"
@@ -16,15 +26,13 @@
 
             <RelativeLayout
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:background="?attr/color_background_primary">
+                android:layout_height="wrap_content">
 
                 <LinearLayout
                     android:id="@+id/linearLayout"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_alignParentStart="true"
-                    android:layout_alignParentLeft="true"
                     android:layout_alignParentBottom="true"
                     android:minHeight="256dp"
                     android:orientation="vertical"
@@ -41,40 +49,38 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/pick_a_server"
-                        android:textAppearance="@style/TextAppearance.Conversations.Title" />
+                        android:textAppearance="?textAppearanceTitleLarge" />
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_marginTop="8dp"
+                        android:layout_marginBottom="16dp"
                         android:text="@string/server_select_text"
-                        android:textAppearance="@style/TextAppearance.Conversations.Body1" />
+                        android:textAppearance="?textAppearanceBodyMedium" />
 
                     <Button
                         android:id="@+id/use_cim"
-                        style="@style/Widget.Conversations.Button.Borderless"
+                        style="@style/Widget.Material3.Button.TonalButton"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_gravity="right"
-                        android:text="@string/use_conversations.im"
-                        android:textColor="?colorAccent" />
+                        android:layout_gravity="end"
+                        android:text="@string/use_conversations.im" />
 
                     <Button
                         android:id="@+id/use_own_provider"
-                        style="@style/Widget.Conversations.Button.Borderless"
+                        style="@style/Widget.Material3.Button.TextButton"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_gravity="right"
-                        android:text="@string/use_own_provider"
-                        android:textColor="?android:textColorSecondary" />
+                        android:layout_gravity="end"
+                        android:text="@string/use_own_provider" />
                 </LinearLayout>
 
                 <RelativeLayout
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
                     android:layout_above="@+id/linearLayout"
-                    android:layout_alignParentStart="true"
-                    android:layout_alignParentLeft="true">
+                    android:layout_alignParentStart="true">
 
                     <ImageView
                         android:layout_width="wrap_content"

src/conversations/res/layout/activity_welcome.xml 🔗

@@ -6,9 +6,18 @@
         android:layout_height="match_parent"
         android:orientation="vertical">
 
-        <include
-            android:id="@+id/toolbar"
-            layout="@layout/toolbar" />
+        <com.google.android.material.appbar.AppBarLayout
+            android:id="@+id/app_bar_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <com.google.android.material.appbar.MaterialToolbar
+                android:id="@+id/toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:minHeight="?attr/actionBarSize" />
+
+        </com.google.android.material.appbar.AppBarLayout>
 
         <ScrollView
             android:layout_width="match_parent"
@@ -17,15 +26,13 @@
 
             <RelativeLayout
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:background="?attr/color_background_primary">
+                android:layout_height="wrap_content">
 
                 <LinearLayout
                     android:id="@+id/linearLayout"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_alignParentStart="true"
-                    android:layout_alignParentLeft="true"
                     android:layout_alignParentBottom="true"
                     android:minHeight="256dp"
                     android:orientation="vertical"
@@ -42,40 +49,38 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:text="@string/welcome_header"
-                        android:textAppearance="@style/TextAppearance.Conversations.Title" />
+                        android:textAppearance="?textAppearanceTitleLarge" />
 
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_marginTop="8dp"
+                        android:layout_marginBottom="16dp"
                         android:text="@string/do_you_have_an_account"
-                        android:textAppearance="@style/TextAppearance.Conversations.Body1" />
+                        android:textAppearance="?textAppearanceBodyMedium" />
 
                     <Button
                         android:id="@+id/register_new_account"
-                        style="@style/Widget.Conversations.Button.Borderless"
+                        style="@style/Widget.Material3.Button.TonalButton"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_gravity="right"
-                        android:text="@string/create_new_account"
-                        android:textColor="?colorAccent" />
+                        android:layout_gravity="end"
+                        android:text="@string/create_new_account" />
 
                     <Button
                         android:id="@+id/use_existing"
-                        style="@style/Widget.Conversations.Button.Borderless"
+                        style="@style/Widget.Material3.Button.TextButton"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_gravity="right"
-                        android:text="@string/i_already_have_an_account"
-                        android:textColor="?android:textColorSecondary" />
+                        android:layout_gravity="end"
+                        android:text="@string/i_already_have_an_account" />
                 </LinearLayout>
 
                 <RelativeLayout
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
                     android:layout_above="@+id/linearLayout"
-                    android:layout_alignParentStart="true"
-                    android:layout_alignParentLeft="true">
+                    android:layout_alignParentStart="true">
 
                     <ImageView
                         android:layout_width="wrap_content"

src/conversations/res/layout/dialog_enter_password.xml 🔗

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto">
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -13,41 +13,35 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/enter_password_to_restore"
-            android:textAppearance="@style/TextAppearance.Conversations.Body2"/>
+            android:textAppearance="?textAppearanceBodyMedium" />
 
         <TextView
-            android:layout_marginTop="?TextSizeBody1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginTop="18sp"
             android:text="@string/restore_warning"
-            android:textAppearance="@style/TextAppearance.Conversations.Body1"/>
+            android:textAppearance="?textAppearanceBodyMedium" />
 
         <TextView
-            android:layout_marginTop="?TextSizeBody1"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginTop="18sp"
             android:text="@string/restore_warning_continued"
-            android:textAppearance="@style/TextAppearance.Conversations.Subhead.Bold"/>
+            android:textAppearance="?textAppearanceBodyMedium" />
 
         <com.google.android.material.textfield.TextInputLayout
             android:id="@+id/account_password_layout"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
-            app:passwordToggleDrawable="@drawable/visibility_toggle_drawable"
-            app:passwordToggleEnabled="true"
-            app:passwordToggleTint="?android:textColorSecondary"
-            app:hintTextAppearance="@style/TextAppearance.Conversations.Design.Hint"
-            app:errorTextAppearance="@style/TextAppearance.Conversations.Design.Error">
+            app:endIconMode="password_toggle">
 
-        <eu.siacs.conversations.ui.widget.TextInputEditText
-            android:id="@+id/account_password"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:hint="@string/password"
-            android:inputType="textPassword"
-            android:textColor="?attr/edit_text_color"
-            style="@style/Widget.Conversations.EditText"/>
+            <eu.siacs.conversations.ui.widget.TextInputEditText
+                android:id="@+id/account_password"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:hint="@string/password"
+                android:inputType="textPassword" />
 
         </com.google.android.material.textfield.TextInputLayout>
     </LinearLayout>

src/conversations/res/menu/manageaccounts.xml 🔗

@@ -1,32 +1,31 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
-	  xmlns:app="http://schemas.android.com/apk/res-auto">
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
-	<item
-		android:id="@+id/action_add_account"
-		android:icon="?attr/icon_add_person"
-		app:showAsAction="always"
-		android:title="@string/action_add_account"/>
-	<item
-		android:id="@+id/action_import_backup"
-		app:showAsAction="never"
-		android:title="@string/restore_backup"/>
-	<item
-		android:id="@+id/action_add_account_with_cert"
-		app:showAsAction="never"
-		android:icon="?attr/icon_add_person"
-		android:title="@string/action_add_account_with_certificate"
-		android:visible="true"/>
-	<item
-		android:id="@+id/action_enable_all"
-		android:title="@string/enable_all_accounts"/>
-	<item
-		android:id="@+id/action_disable_all"
-		android:title="@string/disable_all_accounts"/>
-	<item
-		android:id="@+id/action_settings"
-		android:orderInCategory="100"
-		app:showAsAction="never"
-		android:title="@string/action_settings"/>
+    <item
+        android:id="@+id/action_add_account"
+        android:icon="@drawable/ic_person_add_24dp"
+        android:title="@string/action_add_account"
+        app:showAsAction="ifRoom" />
+    <item
+        android:id="@+id/action_import_backup"
+        android:title="@string/restore_backup"
+        app:showAsAction="never" />
+    <item
+        android:id="@+id/action_add_account_with_cert"
+        android:title="@string/action_add_account_with_certificate"
+        android:visible="true"
+        app:showAsAction="never" />
+    <item
+        android:id="@+id/action_enable_all"
+        android:title="@string/enable_all_accounts" />
+    <item
+        android:id="@+id/action_disable_all"
+        android:title="@string/disable_all_accounts" />
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:title="@string/action_settings"
+        app:showAsAction="never" />
 
 </menu>

src/conversations/res/menu/welcome_menu.xml 🔗

@@ -3,7 +3,7 @@
 
     <item
         android:id="@+id/action_scan_qr_code"
-        android:icon="?attr/icon_scan_qr_code"
+        android:icon="@drawable/ic_qr_code_scanner_24dp"
         android:orderInCategory="10"
         android:title="@string/scan_qr_code"
         android:visible="@bool/show_qr_code_scan"

src/conversations/res/values/colors-themed.xml 🔗

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="md_theme_light_primary">#006E1C</color>
+    <color name="md_theme_light_onPrimary">#FFFFFF</color>
+    <color name="md_theme_light_primaryContainer">#98F994</color>
+    <color name="md_theme_light_onPrimaryContainer">#002204</color>
+    <color name="md_theme_light_secondary">#52634F</color>
+    <color name="md_theme_light_onSecondary">#FFFFFF</color>
+    <color name="md_theme_light_secondaryContainer">#D5E8CF</color>
+    <color name="md_theme_light_onSecondaryContainer">#111F0F</color>
+    <color name="md_theme_light_tertiary">#38656A</color>
+    <color name="md_theme_light_onTertiary">#FFFFFF</color>
+    <color name="md_theme_light_tertiaryContainer">#BCEBF0</color>
+    <color name="md_theme_light_onTertiaryContainer">#002023</color>
+    <color name="md_theme_light_error">#BA1A1A</color>
+    <color name="md_theme_light_errorContainer">#FFDAD6</color>
+    <color name="md_theme_light_onError">#FFFFFF</color>
+    <color name="md_theme_light_onErrorContainer">#410002</color>
+    <color name="md_theme_light_background">#FCFDF6</color>
+    <color name="md_theme_light_onBackground">#1A1C19</color>
+    <color name="md_theme_light_surface">#FCFDF6</color>
+    <color name="md_theme_light_onSurface">#1A1C19</color>
+    <color name="md_theme_light_surfaceVariant">#DEE5D8</color>
+    <color name="md_theme_light_onSurfaceVariant">#424940</color>
+    <color name="md_theme_light_outline">#72796F</color>
+    <color name="md_theme_light_inverseOnSurface">#F0F1EB</color>
+    <color name="md_theme_light_inverseSurface">#2F312D</color>
+    <color name="md_theme_light_inversePrimary">#7DDC7A</color>
+    <color name="md_theme_light_shadow">#000000</color>
+    <color name="md_theme_light_surfaceTint">#006E1C</color>
+    <color name="md_theme_light_outlineVariant">#C2C9BD</color>
+    <color name="md_theme_light_scrim">#000000</color>
+    <color name="md_theme_dark_primary">#7DDC7A</color>
+    <color name="md_theme_dark_onPrimary">#00390A</color>
+    <color name="md_theme_dark_primaryContainer">#005313</color>
+    <color name="md_theme_dark_onPrimaryContainer">#98F994</color>
+    <color name="md_theme_dark_secondary">#BACCB3</color>
+    <color name="md_theme_dark_onSecondary">#253423</color>
+    <color name="md_theme_dark_secondaryContainer">#3B4B38</color>
+    <color name="md_theme_dark_onSecondaryContainer">#D5E8CF</color>
+    <color name="md_theme_dark_tertiary">#A0CFD4</color>
+    <color name="md_theme_dark_onTertiary">#00363B</color>
+    <color name="md_theme_dark_tertiaryContainer">#1F4D52</color>
+    <color name="md_theme_dark_onTertiaryContainer">#BCEBF0</color>
+    <color name="md_theme_dark_error">#FFB4AB</color>
+    <color name="md_theme_dark_errorContainer">#93000A</color>
+    <color name="md_theme_dark_onError">#690005</color>
+    <color name="md_theme_dark_onErrorContainer">#FFDAD6</color>
+    <color name="md_theme_dark_background">#1A1C19</color>
+    <color name="md_theme_dark_onBackground">#E2E3DD</color>
+    <color name="md_theme_dark_surface">#1A1C19</color>
+    <color name="md_theme_dark_onSurface">#E2E3DD</color>
+    <color name="md_theme_dark_surfaceVariant">#424940</color>
+    <color name="md_theme_dark_onSurfaceVariant">#C2C9BD</color>
+    <color name="md_theme_dark_outline">#8C9388</color>
+    <color name="md_theme_dark_inverseOnSurface">#1A1C19</color>
+    <color name="md_theme_dark_inverseSurface">#E2E3DD</color>
+    <color name="md_theme_dark_inversePrimary">#006E1C</color>
+    <color name="md_theme_dark_shadow">#000000</color>
+    <color name="md_theme_dark_surfaceTint">#7DDC7A</color>
+    <color name="md_theme_dark_outlineVariant">#424940</color>
+    <color name="md_theme_dark_scrim">#000000</color>
+</resources>

src/main/AndroidManifest.xml 🔗

@@ -47,7 +47,7 @@
     <!-- this foreground service type permission is exclusively used for import and export backup -->
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
 
-    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
+    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
 
     <uses-feature
         android:name="android.hardware.camera"
@@ -84,6 +84,7 @@
 
 
     <application
+        android:name=".Conversations"
         android:allowBackup="true"
         android:appCategory="social"
         android:dataExtractionRules="@xml/data_extraction_rules"
@@ -96,7 +97,7 @@
         android:networkSecurityConfig="@xml/network_security_configuration"
         android:preserveLegacyExternalStorage="true"
         android:requestLegacyExternalStorage="true"
-        android:theme="@style/ConversationsTheme"
+        android:theme="@style/Theme.Conversations3"
         tools:targetApi="tiramisu">
 
         <meta-data
@@ -132,9 +133,10 @@
             </intent-filter>
         </service>
 
-        <service android:name=".services.CallIntegrationConnectionService"
-            android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
-            android:exported="true">
+        <service
+            android:name=".services.CallIntegrationConnectionService"
+            android:exported="true"
+            android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
             <intent-filter>
                 <action android:name="android.telecom.ConnectionService" />
             </intent-filter>
@@ -180,14 +182,14 @@
         <activity
             android:name=".ui.RecordingActivity"
             android:configChanges="orientation|screenSize"
-            android:theme="@style/ConversationsTheme.Dialog" />
+            android:theme="@style/Theme.Conversations3.Dialog" />
         <activity
             android:name=".ui.ShowLocationActivity"
             android:label="@string/title_activity_show_location" />
         <activity
             android:name=".ui.ConversationActivity"
             android:exported="true"
-            android:theme="@style/SplashTheme">
+            android:theme="@style/Theme.Conversations3.SplashScreen">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
@@ -202,7 +204,7 @@
         <activity
             android:name=".ui.ScanActivity"
             android:screenOrientation="portrait"
-            android:theme="@style/ConversationsTheme.FullScreen"
+            android:theme="@style/Theme.Conversations3.FullScreen"
             android:windowSoftInputMode="stateAlwaysHidden" />
         <activity
             android:name=".ui.UriHandlerActivity"
@@ -263,10 +265,10 @@
         </activity>
         <activity
             android:name=".ui.ChooseContactActivity"
-            android:label="@string/title_activity_choose_contact" />
+            android:label="@string/title_activity_choose_contact"/>
         <activity
             android:name=".ui.BlocklistActivity"
-            android:label="@string/title_activity_block_list" />
+            android:label="@string/title_activity_block_list"/>
         <activity
             android:name=".ui.ChangePasswordActivity"
             android:label="@string/change_password_on_server" />
@@ -351,7 +353,7 @@
 
         <activity
             android:name=".ui.MediaBrowserActivity"
-            android:label="@string/media_browser" />
+            android:label="@string/media_browser"/>
 
         <provider
             android:name="androidx.core.content.FileProvider"
@@ -378,10 +380,10 @@
         </activity>
         <activity
             android:name=".ui.MucUsersActivity"
-            android:label="@string/group_chat_members" />
+            android:label="@string/group_chat_members"/>
         <activity
             android:name=".ui.ChannelDiscoveryActivity"
-            android:label="@string/discover_channels" />
+            android:label="@string/discover_channels"/>
         <activity
             android:name=".ui.RtpSessionActivity"
             android:autoRemoveFromRecents="true"

src/main/java/eu/siacs/conversations/Config.java 🔗

@@ -45,8 +45,6 @@ public final class Config {
 
     public static final Jid BUG_REPORTS = Jid.of("bugs@conversations.im");
     public static final Uri HELP = Uri.parse("https://help.conversations.im");
-
-    public static final String DOMAIN_LOCK = null; // only allow account creation for this domain
     public static final String MAGIC_CREATE_DOMAIN = "conversations.im";
     public static final Jid QUICKSY_DOMAIN = Jid.of("quicksy.im");
 

src/main/java/eu/siacs/conversations/Conversations.java 🔗

@@ -0,0 +1,67 @@
+package eu.siacs.conversations;
+
+import android.app.Application;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import androidx.appcompat.app.AppCompatDelegate;
+
+import com.google.android.material.color.DynamicColors;
+import com.google.android.material.color.DynamicColorsOptions;
+
+public class Conversations extends Application {
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        applyThemeSettings();
+    }
+
+    public void applyThemeSettings() {
+        final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+        if (sharedPreferences == null) {
+            return;
+        }
+        applyThemeSettings(sharedPreferences);
+    }
+
+    private void applyThemeSettings(final SharedPreferences sharedPreferences) {
+        AppCompatDelegate.setDefaultNightMode(getDesiredNightMode(this, sharedPreferences));
+        var dynamicColorsOptions =
+                new DynamicColorsOptions.Builder()
+                        .setPrecondition((activity, t) -> isDynamicColorsDesired(activity))
+                        .build();
+        DynamicColors.applyToActivitiesIfAvailable(this, dynamicColorsOptions);
+    }
+
+    public static int getDesiredNightMode(final Context context) {
+        final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+        if (sharedPreferences == null) {
+            return AppCompatDelegate.getDefaultNightMode();
+        }
+        return getDesiredNightMode(context, sharedPreferences);
+    }
+
+    public static boolean isDynamicColorsDesired(final Context context) {
+        final var preferences = PreferenceManager.getDefaultSharedPreferences(context);
+        return preferences.getBoolean("dynamic_colors", false);
+    }
+
+    private static int getDesiredNightMode(
+            final Context context, final SharedPreferences sharedPreferences) {
+        final String theme =
+                sharedPreferences.getString("theme", context.getString(R.string.theme));
+        return getDesiredNightMode(theme);
+    }
+
+    public static int getDesiredNightMode(final String theme) {
+        if ("automatic".equals(theme)) {
+            return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
+        } else if ("light".equals(theme)) {
+            return AppCompatDelegate.MODE_NIGHT_NO;
+        } else {
+            return AppCompatDelegate.MODE_NIGHT_YES;
+        }
+    }
+}

src/main/java/eu/siacs/conversations/entities/RtpSessionStatus.java 🔗

@@ -41,18 +41,18 @@ public class RtpSessionStatus {
         return new RtpSessionStatus(made, duration);
     }
 
-    public static @DrawableRes int getDrawable(final boolean received, final boolean successful, final boolean darkTheme) {
+    public static @DrawableRes int getDrawable(final boolean received, final boolean successful) {
         if (received) {
             if (successful) {
-                return darkTheme ? R.drawable.ic_call_received_white_18dp : R.drawable.ic_call_received_black_18dp;
+                return R.drawable.ic_call_received_24dp;
             } else {
-                return darkTheme ? R.drawable.ic_call_missed_white_18dp : R.drawable.ic_call_missed_black_18dp;
+                return R.drawable.ic_call_missed_24db;
             }
         } else {
             if (successful) {
-                return darkTheme ? R.drawable.ic_call_made_white_18dp : R.drawable.ic_call_made_black_18dp;
+                return R.drawable.ic_call_made_24dp;
             } else {
-                return darkTheme ? R.drawable.ic_call_missed_outgoing_white_18dp : R.drawable.ic_call_missed_outgoing_black_18dp;
+                return R.drawable.ic_call_missed_outgoing_24dp;
             }
         }
     }

src/main/java/eu/siacs/conversations/services/BarcodeProvider.java 🔗

@@ -48,7 +48,11 @@ public class BarcodeProvider extends ContentProvider implements ServiceConnectio
 		return Uri.parse("content://" + packageId + AUTHORITY + "/" + account.getJid().asBareJid() + ".png");
 	}
 
-	public static Bitmap create2dBarcodeBitmap(String input, int size) {
+	public static Bitmap create2dBarcodeBitmap(final String input, final int size) {
+		return create2dBarcodeBitmap(input, size, Color.BLACK, Color.WHITE);
+	}
+
+	public static Bitmap create2dBarcodeBitmap(final String input, final int size, final int black, final int white) {
 		try {
 			final QRCodeWriter barcodeWriter = new QRCodeWriter();
 			final Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
@@ -61,14 +65,14 @@ public class BarcodeProvider extends ContentProvider implements ServiceConnectio
 			for (int y = 0; y < height; y++) {
 				final int offset = y * width;
 				for (int x = 0; x < width; x++) {
-					pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
+					pixels[offset + x] = result.get(x, y) ? black : white;
 				}
 			}
 			final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 			bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
 			return bitmap;
 		} catch (final Exception e) {
-			e.printStackTrace();
+			Log.e(Config.LOGTAG,"could not generate QR code image",e);
 			return null;
 		}
 	}

src/main/java/eu/siacs/conversations/services/ExportBackupService.java 🔗

@@ -266,7 +266,7 @@ public class ExportBackupService extends Service {
         NotificationCompat.Builder mBuilder =
                 new NotificationCompat.Builder(getBaseContext(), "backup");
         mBuilder.setContentTitle(getString(R.string.notification_create_backup_title))
-                .setSmallIcon(R.drawable.ic_archive_white_24dp)
+                .setSmallIcon(R.drawable.ic_archive_24dp)
                 .setProgress(1, 0, false);
         startForeground(NOTIFICATION_ID, mBuilder.build());
         int count = 0;
@@ -420,11 +420,11 @@ public class ExportBackupService extends Service {
                                                         .getAbsolutePath())))
                 .setAutoCancel(true)
                 .setContentIntent(openFolderIntent)
-                .setSmallIcon(R.drawable.ic_archive_white_24dp);
+                .setSmallIcon(R.drawable.ic_archive_24dp);
 
         if (shareFilesIntent != null) {
             mBuilder.addAction(
-                    R.drawable.ic_share_white_24dp,
+                    R.drawable.ic_share_24dp,
                     getString(R.string.share_backup_files),
                     shareFilesIntent);
         }

src/main/java/eu/siacs/conversations/services/NotificationService.java 🔗

@@ -475,7 +475,7 @@ public class NotificationService {
                 new Builder(mXmppConnectionService, "delivery_failed")
                         .setContentTitle(conversation.getName())
                         .setAutoCancel(true)
-                        .setSmallIcon(R.drawable.ic_error_white_24dp)
+                        .setSmallIcon(R.drawable.ic_error_24dp)
                         .setContentText(
                                 mXmppConnectionService
                                         .getResources()
@@ -495,7 +495,7 @@ public class NotificationService {
                                         .getQuantityText(
                                                 R.plurals.some_messages_could_not_be_delivered,
                                                 1024))
-                        .setSmallIcon(R.drawable.ic_error_white_24dp)
+                        .setSmallIcon(R.drawable.ic_error_24dp)
                         .setGroup("delivery_failed")
                         .setGroupSummary(true)
                         .setAutoCancel(true)
@@ -569,11 +569,11 @@ public class NotificationService {
                 new NotificationCompat.Builder(
                         mXmppConnectionService, INCOMING_CALLS_NOTIFICATION_CHANNEL);
         if (media.contains(Media.VIDEO)) {
-            builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
+            builder.setSmallIcon(R.drawable.ic_videocam_24dp);
             builder.setContentTitle(
                     mXmppConnectionService.getString(R.string.rtp_state_incoming_video_call));
         } else {
-            builder.setSmallIcon(R.drawable.ic_call_white_24dp);
+            builder.setSmallIcon(R.drawable.ic_call_24dp);
             builder.setContentTitle(
                     mXmppConnectionService.getString(R.string.rtp_state_incoming_call));
         }
@@ -596,7 +596,7 @@ public class NotificationService {
         builder.setOngoing(true);
         builder.addAction(
                 new NotificationCompat.Action.Builder(
-                                R.drawable.ic_call_end_white_48dp,
+                                R.drawable.ic_call_end_24dp,
                                 mXmppConnectionService.getString(R.string.dismiss_call),
                                 createCallAction(
                                         id.sessionId,
@@ -605,7 +605,7 @@ public class NotificationService {
                         .build());
         builder.addAction(
                 new NotificationCompat.Action.Builder(
-                                R.drawable.ic_call_white_24dp,
+                                R.drawable.ic_call_24dp,
                                 mXmppConnectionService.getString(R.string.answer_call),
                                 createPendingRtpSession(
                                         id, RtpSessionActivity.ACTION_ACCEPT_CALL, 103))
@@ -622,7 +622,7 @@ public class NotificationService {
         final NotificationCompat.Builder builder =
                 new NotificationCompat.Builder(mXmppConnectionService, "ongoing_calls");
         if (ongoingCall.media.contains(Media.VIDEO)) {
-            builder.setSmallIcon(R.drawable.ic_videocam_white_24dp);
+            builder.setSmallIcon(R.drawable.ic_videocam_24dp);
             if (ongoingCall.reconnecting) {
                 builder.setContentTitle(
                         mXmppConnectionService.getString(R.string.reconnecting_video_call));
@@ -631,7 +631,7 @@ public class NotificationService {
                         mXmppConnectionService.getString(R.string.ongoing_video_call));
             }
         } else {
-            builder.setSmallIcon(R.drawable.ic_call_white_24dp);
+            builder.setSmallIcon(R.drawable.ic_call_24dp);
             if (ongoingCall.reconnecting) {
                 builder.setContentTitle(
                         mXmppConnectionService.getString(R.string.reconnecting_call));
@@ -647,7 +647,7 @@ public class NotificationService {
         builder.setOngoing(true);
         builder.addAction(
                 new NotificationCompat.Action.Builder(
-                                R.drawable.ic_call_end_white_48dp,
+                                R.drawable.ic_call_end_24dp,
                                 mXmppConnectionService.getString(R.string.hang_up),
                                 createCallAction(
                                         id.sessionId, XmppConnectionService.ACTION_END_CALL, 104))
@@ -826,7 +826,7 @@ public class NotificationService {
     }
 
     private void markAsReadIfHasDirectReply(final ArrayList<Message> messages) {
-        if (messages != null && messages.size() > 0) {
+        if (messages != null && !messages.isEmpty()) {
             Message last = messages.get(messages.size() - 1);
             if (last.getStatus() != Message.STATUS_RECEIVED) {
                 if (mXmppConnectionService.markRead((Conversation) last.getConversation(), false)) {
@@ -837,7 +837,8 @@ public class NotificationService {
     }
 
     private void setNotificationColor(final Builder mBuilder) {
-        mBuilder.setColor(ContextCompat.getColor(mXmppConnectionService, R.color.green600));
+        // TODO can we use themed colors?
+        mBuilder.setColor(ContextCompat.getColor(mXmppConnectionService, R.color.md_theme_light_primary));
     }
 
     public void updateNotification() {
@@ -1035,7 +1036,7 @@ public class NotificationService {
         if (!publicVersion) {
             builder.setContentText(Joiner.on(", ").join(names));
         }
-        builder.setSmallIcon(R.drawable.ic_call_missed_white_24db);
+        builder.setSmallIcon(R.drawable.ic_call_missed_24db);
         builder.setGroupSummary(true);
         builder.setGroup(MISSED_CALLS_GROUP);
         builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN);
@@ -1085,7 +1086,7 @@ public class NotificationService {
                                     name));
             builder.setContentText(name);
         }
-        builder.setSmallIcon(R.drawable.ic_call_missed_white_24db);
+        builder.setSmallIcon(R.drawable.ic_call_missed_24db);
         builder.setGroup(MISSED_CALLS_GROUP);
         builder.setCategory(NotificationCompat.CATEGORY_CALL);
         builder.setWhen(info.getLastTime());
@@ -1221,7 +1222,7 @@ public class NotificationService {
             PendingIntent markAsReadPendingIntent = createReadPendingIntent(conversation);
             NotificationCompat.Action markReadAction =
                     new NotificationCompat.Action.Builder(
-                                    R.drawable.ic_drafts_white_24dp,
+                                    R.drawable.ic_mark_chat_read_24dp,
                                     mXmppConnectionService.getString(R.string.mark_as_read),
                                     markAsReadPendingIntent)
                             .setSemanticAction(
@@ -1232,7 +1233,7 @@ public class NotificationService {
             final String lastMessageUuid = Iterables.getLast(messages).getUuid();
             final NotificationCompat.Action replyAction =
                     new NotificationCompat.Action.Builder(
-                                    R.drawable.ic_send_text_offline,
+                                    R.drawable.ic_send_24dp,
                                     replyLabel,
                                     createReplyIntent(conversation, lastMessageUuid, false))
                             .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
@@ -1241,7 +1242,7 @@ public class NotificationService {
                             .build();
             final NotificationCompat.Action wearReplyAction =
                     new NotificationCompat.Action.Builder(
-                                    R.drawable.ic_wear_reply,
+                                    R.drawable.ic_reply_24dp,
                                     replyLabel,
                                     createReplyIntent(conversation, lastMessageUuid, true))
                             .addRemoteInput(remoteInput)
@@ -1260,7 +1261,7 @@ public class NotificationService {
                 PendingIntent pendingSnoozeIntent = createSnoozeIntent(conversation);
                 NotificationCompat.Action snoozeAction =
                         new NotificationCompat.Action.Builder(
-                                        R.drawable.ic_notifications_paused_white_24dp,
+                                        R.drawable.ic_notifications_paused_24dp,
                                         label,
                                         pendingSnoozeIntent)
                                 .build();
@@ -1279,7 +1280,7 @@ public class NotificationService {
                                         .getString(R.string.show_location);
                         NotificationCompat.Action locationAction =
                                 new NotificationCompat.Action.Builder(
-                                                R.drawable.ic_room_white_24dp,
+                                                R.drawable.ic_location_pin_24dp,
                                                 label,
                                                 pendingShowLocationIntent)
                                         .build();
@@ -1303,7 +1304,7 @@ public class NotificationService {
                             createDownloadIntent(firstDownloadableMessage);
                     NotificationCompat.Action downloadAction =
                             new NotificationCompat.Action.Builder(
-                                            R.drawable.ic_file_download_white_24dp,
+                                            R.drawable.ic_download_24dp,
                                             label,
                                             pendingDownloadIntent)
                                     .build();
@@ -1761,21 +1762,21 @@ public class NotificationService {
                 .setPriority(Notification.PRIORITY_MIN)
                 .setSmallIcon(
                         connected > 0
-                                ? R.drawable.ic_link_white_24dp
-                                : R.drawable.ic_link_off_white_24dp)
+                                ? R.drawable.ic_link_24dp
+                                : R.drawable.ic_link_off_24dp)
                 .setLocalOnly(true);
 
         if (Compatibility.runsTwentySix()) {
             mBuilder.setChannelId("foreground");
             mBuilder.addAction(
-                    R.drawable.ic_logout_white_24dp,
+                    R.drawable.ic_logout_24dp,
                     mXmppConnectionService.getString(R.string.log_out),
                     pendingServiceIntent(
                             mXmppConnectionService,
                             XmppConnectionService.ACTION_TEMPORARILY_DISABLE,
                             87));
             mBuilder.addAction(
-                    R.drawable.ic_notifications_off_white_24dp,
+                    R.drawable.ic_notifications_off_24dp,
                     mXmppConnectionService.getString(R.string.hide_notification),
                     pendingNotificationSettingsIntent(mXmppConnectionService));
         }
@@ -1853,7 +1854,7 @@ public class NotificationService {
         }
         try {
             mBuilder.addAction(
-                    R.drawable.ic_autorenew_white_24dp,
+                    R.drawable.ic_autorenew_24dp,
                     mXmppConnectionService.getString(R.string.try_again),
                     pendingServiceIntent(
                             mXmppConnectionService, XmppConnectionService.ACTION_TRY_AGAIN, 45));
@@ -1871,7 +1872,7 @@ public class NotificationService {
         if (torNotAvailable) {
             if (TorServiceUtils.isOrbotInstalled(mXmppConnectionService)) {
                 mBuilder.addAction(
-                        R.drawable.ic_play_circle_filled_white_48dp,
+                        R.drawable.ic_play_circle_24dp,
                         mXmppConnectionService.getString(R.string.start_orbot),
                         PendingIntent.getActivity(
                                 mXmppConnectionService,
@@ -1883,7 +1884,7 @@ public class NotificationService {
                                         : PendingIntent.FLAG_UPDATE_CURRENT));
             } else {
                 mBuilder.addAction(
-                        R.drawable.ic_file_download_white_24dp,
+                        R.drawable.ic_download_24dp,
                         mXmppConnectionService.getString(R.string.install_orbot),
                         PendingIntent.getActivity(
                                 mXmppConnectionService,
@@ -1896,7 +1897,7 @@ public class NotificationService {
             }
         }
         mBuilder.setVisibility(Notification.VISIBILITY_PRIVATE);
-        mBuilder.setSmallIcon(R.drawable.ic_warning_white_24dp);
+        mBuilder.setSmallIcon(R.drawable.ic_warning_24dp);
         mBuilder.setLocalOnly(true);
         mBuilder.setPriority(Notification.PRIORITY_LOW);
         final Intent intent;
@@ -1935,7 +1936,7 @@ public class NotificationService {
         } else {
             builder.setProgress(100, 0, true);
         }
-        builder.setSmallIcon(R.drawable.ic_hourglass_empty_white_24dp);
+        builder.setSmallIcon(R.drawable.ic_hourglass_top_24dp);
         if (message != null) {
             builder.setContentIntent(createContentIntent(message.getConversation()));
         }

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -4760,9 +4760,6 @@ public class XmppConnectionService extends Service {
         if (Config.QUICKSY_DOMAIN != null) {
             hosts.remove(Config.QUICKSY_DOMAIN.toEscapedString()); //we only want to show this when we type a e164 number
         }
-        if (Config.DOMAIN_LOCK != null) {
-            hosts.add(Config.DOMAIN_LOCK);
-        }
         if (Config.MAGIC_CREATE_DOMAIN != null) {
             hosts.add(Config.MAGIC_CREATE_DOMAIN);
         }

src/main/java/eu/siacs/conversations/ui/AboutActivity.java 🔗

@@ -1,31 +1,25 @@
 package eu.siacs.conversations.ui;
 
+import static eu.siacs.conversations.ui.XmppActivity.configureActionBar;
+
 import android.os.Bundle;
 
-import androidx.appcompat.app.AppCompatActivity;
+import androidx.databinding.DataBindingUtil;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.ui.util.SettingsUtils;
-import eu.siacs.conversations.utils.ThemeHelper;
-
-import static eu.siacs.conversations.ui.XmppActivity.configureActionBar;
+import eu.siacs.conversations.databinding.ActivityAboutBinding;
 
-public class AboutActivity extends AppCompatActivity {
+public class AboutActivity extends BaseActivity {
 
-    @Override
-    protected void onResume(){
-        super.onResume();
-        SettingsUtils.applyScreenshotPreventionSetting(this);
-    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        setTheme(ThemeHelper.find(this));
+        final ActivityAboutBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_about);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
 
-        setContentView(R.layout.activity_about);
-        setSupportActionBar(findViewById(R.id.toolbar));
+        setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
         setTitle(getString(R.string.title_activity_about_x, getString(R.string.app_name)));
     }

src/main/java/eu/siacs/conversations/ui/AbstractSearchableListItemActivity.java 🔗

@@ -14,6 +14,7 @@ import android.widget.EditText;
 import android.widget.ListView;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.databinding.DataBindingUtil;
 
 import java.util.ArrayList;
@@ -34,7 +35,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
 	private final MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() {
 
 		@Override
-		public boolean onMenuItemActionExpand(final MenuItem item) {
+		public boolean onMenuItemActionExpand(@NonNull final MenuItem item) {
 			mSearchEditText.post(() -> {
 				mSearchEditText.requestFocus();
 				final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -45,7 +46,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
 		}
 
 		@Override
-		public boolean onMenuItemActionCollapse(final MenuItem item) {
+		public boolean onMenuItemActionCollapse(@NonNull final MenuItem item) {
 			final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
 			imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
 			mSearchEditText.setText("");
@@ -92,6 +93,7 @@ public abstract class AbstractSearchableListItemActivity extends XmppActivity im
 	public void onCreate(final Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		this.binding = DataBindingUtil.setContentView(this,R.layout.activity_choose_contact);
+		Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
 		setSupportActionBar(binding.toolbar);
 		configureActionBar(getSupportActionBar());
 		this.binding.chooseContactList.setFastScrollEnabled(true);

src/main/java/eu/siacs/conversations/ui/ActionBarActivity.java 🔗

@@ -8,7 +8,7 @@ import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.widget.Toolbar;
 
 
-public abstract class ActionBarActivity extends AppCompatActivity {
+public abstract class ActionBarActivity extends BaseActivity {
     public static void configureActionBar(ActionBar actionBar) {
         configureActionBar(actionBar, true);
     }

src/main/java/eu/siacs/conversations/ui/Activities.java 🔗

@@ -0,0 +1,47 @@
+package eu.siacs.conversations.ui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Build;
+import android.view.View;
+import com.google.android.material.elevation.SurfaceColors;
+
+public final class Activities {
+
+    private Activities() {}
+
+    public static void setStatusAndNavigationBarColors(final Activity activity, final View view) {
+        setStatusAndNavigationBarColors(activity, view, false);
+    }
+
+    public static void setStatusAndNavigationBarColors(
+            final Activity activity, final View view, final boolean raisedStatusBar) {
+        final var isLightMode = isLightMode(activity);
+        final var window = activity.getWindow();
+        final var flags = view.getSystemUiVisibility();
+        // an elevation of 4 matches the MaterialToolbar elevation
+        if (raisedStatusBar) {
+            window.setStatusBarColor(SurfaceColors.SURFACE_5.getColor(activity));
+        } else {
+            window.setStatusBarColor(SurfaceColors.SURFACE_0.getColor(activity));
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            window.setNavigationBarColor(SurfaceColors.SURFACE_1.getColor(activity));
+            if (isLightMode) {
+                view.setSystemUiVisibility(
+                        flags
+                                | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
+                                | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+            }
+        } else if (isLightMode) {
+            view.setSystemUiVisibility(flags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+        }
+    }
+
+    private static boolean isLightMode(final Context context) {
+        final int nightModeFlags =
+                context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        return nightModeFlags != Configuration.UI_MODE_NIGHT_YES;
+    }
+}

src/main/java/eu/siacs/conversations/ui/BaseActivity.java 🔗

@@ -0,0 +1,53 @@
+package eu.siacs.conversations.ui;
+
+import android.util.Log;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatDelegate;
+
+import eu.siacs.conversations.Conversations;
+import eu.siacs.conversations.ui.util.SettingsUtils;
+
+public abstract class BaseActivity extends AppCompatActivity {
+    private Boolean isDynamicColors;
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        final int desiredNightMode = Conversations.getDesiredNightMode(this);
+        if (setDesiredNightMode(desiredNightMode)) {
+            return;
+        }
+        final boolean isDynamicColors = Conversations.isDynamicColorsDesired(this);
+        setDynamicColors(isDynamicColors);
+    }
+
+    @Override
+    protected void onResume(){
+        super.onResume();
+        SettingsUtils.applyScreenshotPreventionSetting(this);
+    }
+
+    public void setDynamicColors(final boolean isDynamicColors) {
+        if (this.isDynamicColors == null) {
+            this.isDynamicColors = isDynamicColors;
+        } else {
+            if (this.isDynamicColors != isDynamicColors) {
+                Log.i(
+                        "Recreating {} because dynamic color setting has changed",
+                        getClass().getSimpleName());
+                recreate();
+            }
+        }
+    }
+
+    public boolean setDesiredNightMode(final int desiredNightMode) {
+        if (desiredNightMode == AppCompatDelegate.getDefaultNightMode()) {
+            return false;
+        }
+        AppCompatDelegate.setDefaultNightMode(desiredNightMode);
+        Log.i("Recreating {} because desired night mode has changed", getClass().getSimpleName());
+        recreate();
+        return true;
+    }
+}

src/main/java/eu/siacs/conversations/ui/BlockContactDialog.java 🔗

@@ -7,6 +7,8 @@ import androidx.annotation.StringRes;
 import androidx.appcompat.app.AlertDialog;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.DialogBlockContactBinding;
 import eu.siacs.conversations.entities.Blockable;
@@ -19,7 +21,7 @@ public final class BlockContactDialog {
 		show(xmppActivity, blockable, null);
 	}
 	public static void show(final XmppActivity xmppActivity, final Blockable blockable, final String serverMsgId) {
-		final AlertDialog.Builder builder = new AlertDialog.Builder(xmppActivity);
+		final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(xmppActivity);
 		final boolean isBlocked = blockable.isBlocked();
 		builder.setNegativeButton(R.string.cancel, null);
 		DialogBlockContactBinding binding = DataBindingUtil.inflate(xmppActivity.getLayoutInflater(), R.layout.dialog_block_contact, null, false);

src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java 🔗

@@ -3,86 +3,84 @@ package eu.siacs.conversations.ui;
 import android.content.Intent;
 import android.os.Bundle;
 import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
 import android.widget.Toast;
 
+import androidx.databinding.DataBindingUtil;
+
 import com.google.android.material.textfield.TextInputLayout;
 
 import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityChangePasswordBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.widget.DisabledActionModeCallback;
 
 public class ChangePasswordActivity extends XmppActivity implements XmppConnectionService.OnAccountPasswordChanged {
 
-	private Button mChangePasswordButton;
+	private ActivityChangePasswordBinding binding;
+
 	private final View.OnClickListener mOnChangePasswordButtonClicked = new View.OnClickListener() {
 		@Override
-		public void onClick(View view) {
-			if (mAccount != null) {
-				final String currentPassword = mCurrentPassword.getText().toString();
-				final String newPassword = mNewPassword.getText().toString();
-				if (!mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(mAccount.getPassword())) {
-					mCurrentPassword.requestFocus();
-					mCurrentPasswordLayout.setError(getString(R.string.account_status_unauthorized));
-					removeErrorsOnAllBut(mCurrentPasswordLayout);
+		public void onClick(final View view) {
+			final var account = mAccount;
+			if (account == null) {
+				return;
+			}
+				final String currentPassword = binding.currentPassword.getText().toString();
+				final String newPassword = binding.newPassword.getText().toString();
+				if (!account.isOptionSet(Account.OPTION_MAGIC_CREATE) && !currentPassword.equals(account.getPassword())) {
+					binding.currentPassword.requestFocus();
+					binding.currentPasswordLayout.setError(getString(R.string.account_status_unauthorized));
+					removeErrorsOnAllBut(binding.currentPasswordLayout);
 				} else if (newPassword.trim().isEmpty()) {
-					mNewPassword.requestFocus();
-					mNewPasswordLayout.setError(getString(R.string.password_should_not_be_empty));
-					removeErrorsOnAllBut(mNewPasswordLayout);
+					binding.newPassword.requestFocus();
+					binding.newPasswordLayout.setError(getString(R.string.password_should_not_be_empty));
+					removeErrorsOnAllBut(binding.newPasswordLayout);
 				} else {
-					mCurrentPasswordLayout.setError(null);
-					mNewPasswordLayout.setError(null);
-					xmppConnectionService.updateAccountPasswordOnServer(mAccount, newPassword, ChangePasswordActivity.this);
-					mChangePasswordButton.setEnabled(false);
-					mChangePasswordButton.setText(R.string.updating);
+					binding.currentPasswordLayout.setError(null);
+					binding.newPasswordLayout.setError(null);
+					xmppConnectionService.updateAccountPasswordOnServer(account, newPassword, ChangePasswordActivity.this);
+					binding.changePasswordButton.setEnabled(false);
+					binding.changePasswordButton.setText(R.string.updating);
 				}
-			}
 		}
 	};
-	private EditText mCurrentPassword;
-	private EditText mNewPassword;
-	private TextInputLayout mNewPasswordLayout;
-	private TextInputLayout mCurrentPasswordLayout;
+
+
+
 	private Account mAccount;
 
 	@Override
 	void onBackendConnected() {
 		this.mAccount = extractAccount(getIntent());
 		if (this.mAccount != null && this.mAccount.isOptionSet(Account.OPTION_MAGIC_CREATE)) {
-			this.mCurrentPasswordLayout.setVisibility(View.GONE);
+			this.binding.currentPasswordLayout.setVisibility(View.GONE);
 		} else {
-			this.mCurrentPassword.setVisibility(View.VISIBLE);
+			this.binding.currentPasswordLayout.setVisibility(View.VISIBLE);
 		}
 	}
 
 	@Override
 	protected void onCreate(final Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
-		setContentView(R.layout.activity_change_password);
-		setSupportActionBar(findViewById(R.id.toolbar));
+		this.binding = DataBindingUtil.setContentView(this, R.layout.activity_change_password);
+		Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+		setSupportActionBar(binding.toolbar);
 		configureActionBar(getSupportActionBar());
-		Button mCancelButton = findViewById(R.id.left_button);
-		mCancelButton.setOnClickListener(view -> finish());
-		this.mChangePasswordButton = findViewById(R.id.right_button);
-		this.mChangePasswordButton.setOnClickListener(this.mOnChangePasswordButtonClicked);
-		this.mCurrentPassword = findViewById(R.id.current_password);
-		this.mCurrentPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
-		this.mNewPassword = findViewById(R.id.new_password);
-		this.mNewPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
-		this.mCurrentPasswordLayout = findViewById(R.id.current_password_layout);
-		this.mNewPasswordLayout = findViewById(R.id.new_password_layout);
+		binding.cancelButton.setOnClickListener(view -> finish());
+		binding.changePasswordButton.setOnClickListener(this.mOnChangePasswordButtonClicked);
+		binding.currentPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
+		binding.newPassword.setCustomSelectionActionModeCallback(new DisabledActionModeCallback());
 	}
 
 	@Override
-	protected void onStart() {
+	public void onStart() {
 		super.onStart();
 		Intent intent = getIntent();
 		String password = intent != null ? intent.getStringExtra("password") : null;
 		if (password != null) {
-			this.mNewPassword.getEditableText().clear();
-			this.mNewPassword.getEditableText().append(password);
+			binding.newPassword.getEditableText().clear();
+			binding.newPassword.getEditableText().append(password);
 		}
 	}
 
@@ -97,21 +95,21 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti
 	@Override
 	public void onPasswordChangeFailed() {
 		runOnUiThread(() -> {
-			mNewPasswordLayout.setError(getString(R.string.could_not_change_password));
-			mChangePasswordButton.setEnabled(true);
-			mChangePasswordButton.setText(R.string.change_password);
+			binding.newPasswordLayout.setError(getString(R.string.could_not_change_password));
+			binding.changePasswordButton.setEnabled(true);
+			binding.changePasswordButton.setText(R.string.change_password);
 		});
 
 	}
 
 	private void removeErrorsOnAllBut(TextInputLayout exception) {
-		if (this.mCurrentPasswordLayout != exception) {
-			this.mCurrentPasswordLayout.setErrorEnabled(false);
-			this.mCurrentPasswordLayout.setError(null);
+		if (this.binding.currentPasswordLayout != exception) {
+			this.binding.currentPasswordLayout.setErrorEnabled(false);
+			this.binding.currentPasswordLayout.setError(null);
 		}
-		if (this.mNewPasswordLayout != exception) {
-			this.mNewPasswordLayout.setErrorEnabled(false);
-			this.mNewPasswordLayout.setError(null);
+		if (this.binding.newPasswordLayout != exception) {
+			this.binding.newPasswordLayout.setErrorEnabled(false);
+			this.binding.newPasswordLayout.setError(null);
 		}
 
 	}

src/main/java/eu/siacs/conversations/ui/ChannelDiscoveryActivity.java 🔗

@@ -19,8 +19,11 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
 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 java.util.Collections;
@@ -39,7 +42,6 @@ import eu.siacs.conversations.services.QuickConversationsService;
 import eu.siacs.conversations.ui.adapter.ChannelSearchResultAdapter;
 import eu.siacs.conversations.ui.util.PendingItem;
 import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.AccountUtils;
 import eu.siacs.conversations.xmpp.Jid;
 
@@ -81,6 +83,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
         super.onCreate(savedInstanceState);
         binding = DataBindingUtil.setContentView(this, R.layout.activity_channel_discovery);
         setSupportActionBar(binding.toolbar);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         configureActionBar(getSupportActionBar(), true);
         binding.list.setAdapter(this.adapter);
         this.adapter.setOnChannelSearchResultSelectedListener(this);
@@ -155,7 +158,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
     private void toggleLoadingScreen() {
         adapter.submitList(Collections.emptyList());
         binding.progressBar.setVisibility(View.VISIBLE);
-        binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary));
+        binding.list.setBackgroundColor(MaterialColors.getColor(binding.list, com.google.android.material.R.attr.colorSurface));
     }
 
     @Override
@@ -163,13 +166,13 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
         super.onStart();
         this.method = getMethod(this);
         if (!optedIn && method == ChannelDiscoveryService.Method.JABBER_NETWORK) {
-            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
             builder.setTitle(R.string.channel_discovery_opt_in_title);
             builder.setMessage(Html.fromHtml(getString(R.string.channel_discover_opt_in_message)));
             builder.setNegativeButton(R.string.cancel, (dialog, which) -> finish());
             builder.setPositiveButton(R.string.confirm, (dialog, which) -> optIn());
             builder.setOnCancelListener(dialog -> finish());
-            final AlertDialog dialog = builder.create();
+            final androidx.appcompat.app.AlertDialog dialog = builder.create();
             dialog.setOnShowListener(d -> {
                 final TextView textView = dialog.findViewById(android.R.id.message);
                 if (textView == null) {
@@ -186,7 +189,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
     private void holdLoading() {
         adapter.submitList(Collections.emptyList());
         binding.progressBar.setVisibility(View.GONE);
-        binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary));
+        binding.list.setBackgroundColor(MaterialColors.getColor(binding.list, com.google.android.material.R.attr.colorSurface));
     }
 
     @Override
@@ -220,10 +223,10 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
         runOnUiThread(() -> {
             adapter.submitList(results);
             binding.progressBar.setVisibility(View.GONE);
-            if (results.size() == 0) {
-                binding.list.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_primary_background_no_results));
+            if (results.isEmpty()) {
+                binding.list.setBackground(ContextCompat.getDrawable(this,R.drawable.background_no_results));
             } else {
-                binding.list.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_primary));
+                binding.list.setBackgroundColor(MaterialColors.getColor(binding.list, com.google.android.material.R.attr.colorSurface));
             }
         });
 
@@ -234,11 +237,11 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
         final List<String> accounts = AccountUtils.getEnabledAccounts(xmppConnectionService);
         if (accounts.size() == 1) {
             joinChannelSearchResult(accounts.get(0), result);
-        } else if (accounts.size() == 0) {
+        } else if (accounts.isEmpty()) {
             Toast.makeText(this, R.string.please_enable_an_account, Toast.LENGTH_LONG).show();
         } else {
             final AtomicReference<String> account = new AtomicReference<>(accounts.get(0));
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
             builder.setTitle(R.string.choose_account);
             builder.setSingleChoiceItems(accounts.toArray(new CharSequence[0]), 0, (dialog, which) -> account.set(accounts.get(which)));
             builder.setPositiveButton(R.string.join, (dialog, which) -> joinChannelSearchResult(account.get(), result));
@@ -271,10 +274,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
     }
 
     public void joinChannelSearchResult(final String selectedAccount, final Room result) {
-        final Jid jid =
-                Config.DOMAIN_LOCK == null
-                        ? Jid.ofEscaped(selectedAccount)
-                        : Jid.ofLocalAndDomainEscaped(selectedAccount, Config.DOMAIN_LOCK);
+        final Jid jid = Jid.ofEscaped(selectedAccount);
         final boolean syncAutoJoin = getBooleanPreference("autojoin", R.bool.autojoin);
         final Account account = xmppConnectionService.findAccountByJid(jid);
         final Conversation conversation =

src/main/java/eu/siacs/conversations/ui/ChooseAccountForProfilePictureActivity.java 🔗

@@ -3,20 +3,21 @@ package eu.siacs.conversations.ui;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.widget.ListView;
 import android.widget.Toast;
 
-import java.util.ArrayList;
-import java.util.List;
+import androidx.databinding.DataBindingUtil;
 
 import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityManageAccountsBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.ui.adapter.AccountAdapter;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class ChooseAccountForProfilePictureActivity extends XmppActivity {
 
     protected final List<Account> accountList = new ArrayList<>();
-    protected ListView accountListView;
     protected AccountAdapter mAccountAdapter;
 
     @Override
@@ -28,25 +29,21 @@ public class ChooseAccountForProfilePictureActivity extends XmppActivity {
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_manage_accounts);
-        setSupportActionBar(findViewById(R.id.toolbar));
+        final ActivityManageAccountsBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_manage_accounts);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+        setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar(), false);
-        accountListView = findViewById(R.id.account_list);
         this.mAccountAdapter = new AccountAdapter(this, accountList, false);
-        accountListView.setAdapter(this.mAccountAdapter);
-        accountListView.setOnItemClickListener((arg0, view, position, arg3) -> {
+        binding.accountList.setAdapter(this.mAccountAdapter);
+        binding.accountList.setOnItemClickListener((arg0, view, position, arg3) -> {
             final Account account = accountList.get(position);
             goToProfilePictureActivity(account);
         });
     }
 
     @Override
-    protected void onStart() {
+    public void onStart() {
         super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        }
     }
 
     @Override

src/main/java/eu/siacs/conversations/ui/ChooseContactActivity.java 🔗

@@ -9,6 +9,7 @@ import android.view.ActionMode;
 import android.view.KeyEvent;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AbsListView.MultiChoiceModeListener;
@@ -51,7 +52,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     public static final String EXTRA_SHOW_ENTER_JID = "extra_show_enter_jid";
     public static final String EXTRA_CONVERSATION = "extra_conversation";
     private static final String EXTRA_FILTERED_CONTACTS = "extra_filtered_contacts";
-    private final List<String> mActivatedAccounts = new ArrayList<>();
+    private final ArrayList<String> mActivatedAccounts = new ArrayList<>();
     private final Set<String> selected = new HashSet<>();
     private Set<String> filterContacts;
 
@@ -130,7 +131,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
         if (this.showEnterJid) {
             this.binding.fab.show();
         } else {
-            binding.fab.setImageResource(R.drawable.ic_forward_white_24dp);
+            binding.fab.setImageResource(R.drawable.ic_navigate_next_24dp);
         }
 
         final SharedPreferences preferences = getPreferences();
@@ -139,7 +140,7 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     }
 
     private void onFabClicked(View v) {
-        if (selected.size() == 0) {
+        if (selected.isEmpty()) {
             showEnterJidDialog(null);
         } else {
             submitSelection();
@@ -154,7 +155,8 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     @Override
     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
         mode.setTitle(getTitleFromIntent());
-        binding.fab.setImageResource(R.drawable.ic_forward_white_24dp);
+        binding.chooseContactList.setFastScrollEnabled(false);
+        binding.fab.setImageResource(R.drawable.ic_navigate_next_24dp);
         binding.fab.show();
         final View view = getSearchEditText();
         final InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -166,12 +168,13 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
 
     @Override
     public void onDestroyActionMode(ActionMode mode) {
-        this.binding.fab.setImageResource(R.drawable.ic_person_add_white_24dp);
+        this.binding.fab.setImageResource(R.drawable.ic_person_add_24dp);
         if (this.showEnterJid) {
             this.binding.fab.show();
         } else {
             this.binding.fab.hide();
         }
+        binding.chooseContactList.setFastScrollEnabled(true);
         selected.clear();
     }
 
@@ -199,8 +202,9 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     @Override
     public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
         if (selected.size() != 0) {
-            getListView().playSoundEffect(0);
+            getListView().playSoundEffect(SoundEffectConstants.CLICK);
         }
+        getListItemAdapter().notifyDataSetChanged();
         Contact item = (Contact) getListItems().get(position);
         if (checked) {
             selected.add(item.getJid().toString());
@@ -361,13 +365,9 @@ public class ChooseContactActivity extends AbstractSearchableListItemActivity im
     void onBackendConnected() {
         filterContacts();
         this.mActivatedAccounts.clear();
-        for (Account account : xmppConnectionService.getAccounts()) {
+        for (final Account account : xmppConnectionService.getAccounts()) {
             if (account.isEnabled()) {
-                if (Config.DOMAIN_LOCK != null) {
-                    this.mActivatedAccounts.add(account.getJid().getEscapedLocal());
-                } else {
-                    this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
-                }
+                this.mActivatedAccounts.add(account.getJid().asBareJid().toEscapedString());
             }
         }
         ActivityResult activityResult = this.postponedActivityResult.pop();

src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java 🔗

@@ -55,6 +55,8 @@ 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 static final String ACTION_VIEW_MUC = "view_muc";
 
@@ -97,7 +99,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
     private final OnClickListener mNotifyStatusClickListener = new OnClickListener() {
         @Override
         public void onClick(View v) {
-            AlertDialog.Builder builder = new AlertDialog.Builder(ConferenceDetailsActivity.this);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ConferenceDetailsActivity.this);
             builder.setTitle(R.string.pref_notification_settings);
             String[] choices = {
                     getString(R.string.notify_on_all_messages),
@@ -130,7 +132,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
         @Override
         public void onClick(View v) {
             final MucOptions mucOptions = mConversation.getMucOptions();
-            AlertDialog.Builder builder = new AlertDialog.Builder(ConferenceDetailsActivity.this);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(ConferenceDetailsActivity.this);
             MucConfiguration configuration = MucConfiguration.get(ConferenceDetailsActivity.this, mAdvancedMode, mucOptions);
             builder.setTitle(configuration.title);
             final boolean[] values = configuration.values;
@@ -168,6 +170,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_details);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         this.binding.changeConferenceButton.setOnClickListener(this.mChangeConferenceSettings);
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
@@ -216,12 +219,8 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
     }
 
     @Override
-    protected void onStart() {
+    public void onStart() {
         super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        }
         binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE);
     }
 
@@ -277,7 +276,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
             final MucOptions mucOptions = mConversation.getMucOptions();
             this.binding.mucEditor.setVisibility(View.VISIBLE);
             this.binding.mucDisplay.setVisibility(View.GONE);
-            this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp));
+            this.binding.editMucNameButton.setImageResource(R.drawable.ic_cancel_24dp);
             final String name = mucOptions.getName();
             this.binding.mucEditTitle.setText("");
             final boolean owner = mucOptions.getSelf().getAffiliation().ranks(MucOptions.Affiliation.OWNER);
@@ -311,7 +310,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
     private void hideEditor() {
         this.binding.mucEditor.setVisibility(View.GONE);
         this.binding.mucDisplay.setVisibility(View.VISIBLE);
-        this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_edit_body, R.drawable.ic_edit_black_24dp));
+        this.binding.editMucNameButton.setImageResource(R.drawable.ic_edit_24dp);
     }
 
     private void onMucInfoUpdated(String subject, String name) {
@@ -384,7 +383,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
 
     protected void destroyRoom() {
         final boolean groupChat = mConversation != null && mConversation.isPrivateAndNonAnonymous();
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        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) -> {
@@ -434,12 +433,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
         }
         final MucOptions mucOptions = mConversation.getMucOptions();
         final User self = mucOptions.getSelf();
-        String account;
-        if (Config.DOMAIN_LOCK != null) {
-            account = mConversation.getAccount().getJid().getEscapedLocal();
-        } else {
-            account = mConversation.getAccount().getJid().asBareJid().toEscapedString();
-        }
+        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);
         this.binding.detailsAccount.setText(getString(R.string.using_account, account));
@@ -469,7 +463,7 @@ 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(this, subject.length() > (hasTitle ? 128 : 196) ? R.style.TextAppearance_Conversations_Body1_Linkified : R.style.TextAppearance_Conversations_Subhead);
+            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());
@@ -507,24 +501,19 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
             this.binding.mucSettings.setVisibility(View.GONE);
         }
 
-        int ic_notifications = getThemeResource(R.attr.icon_notifications, R.drawable.ic_notifications_black_24dp);
-        int ic_notifications_off = getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp);
-        int ic_notifications_paused = getThemeResource(R.attr.icon_notifications_paused, R.drawable.ic_notifications_paused_black_24dp);
-        int ic_notifications_none = getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp);
-
-        long mutedTill = mConversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
+        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(ic_notifications_off);
+            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(ic_notifications_paused);
+            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(ic_notifications);
+            this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_24dp);
         } else {
             this.binding.notificationStatusText.setText(R.string.notify_only_when_highlighted);
-            this.binding.notificationStatusButton.setImageResource(ic_notifications_none);
+            this.binding.notificationStatusButton.setImageResource(R.drawable.ic_notifications_none_24dp);
         }
         final List<User> users = mucOptions.getUsers();
         Collections.sort(users, (a, b) -> {
@@ -629,9 +618,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
             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(getThemeResource(R.attr.icon_save, R.drawable.ic_save_black_24dp));
+                this.binding.editMucNameButton.setImageResource(R.drawable.ic_save_24dp);
             } else {
-                this.binding.editMucNameButton.setImageResource(getThemeResource(R.attr.icon_cancel, R.drawable.ic_cancel_black_24dp));
+                this.binding.editMucNameButton.setImageResource(R.drawable.ic_cancel_24dp);
             }
         }
     }

src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java 🔗

@@ -30,6 +30,9 @@ import androidx.annotation.NonNull;
 import androidx.appcompat.app.AlertDialog;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.color.MaterialColors;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import org.openintents.openpgp.util.OpenPgpUtils;
 
 import java.util.Collection;
@@ -144,7 +147,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
         } else {
             value = jid.toEscapedString();
         }
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         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);
@@ -215,6 +218,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
         }
         this.messageFingerprint = getIntent().getStringExtra("fingerprint");
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_contact_details);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
 
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
@@ -238,14 +242,9 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
     @Override
     public void onStart() {
         super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        } else {
-            final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
-            this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
-            this.showLastSeen = preferences.getBoolean("last_activity", false);
-        }
+        final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+        this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
+        this.showLastSeen = preferences.getBoolean("last_activity", false);
         binding.mediaWrapper.setVisibility(Compatibility.hasStoragePermission(this) ? View.VISIBLE : View.GONE);
         mMediaAdapter.setAttachments(Collections.emptyList());
     }
@@ -268,8 +267,6 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
         if (MenuDoubleTabUtil.shouldIgnoreTap()) {
             return false;
         }
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setNegativeButton(getString(R.string.cancel), null);
         switch (menuItem.getItemId()) {
             case android.R.id.home:
                 finish();
@@ -281,6 +278,8 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
                 shareLink(false);
                 break;
             case R.id.action_delete_contact:
+                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),
@@ -431,12 +430,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
         }
 
         binding.detailsContactjid.setText(IrregularUnicodeDetector.style(this, contact.getJid()));
-        String account;
-        if (Config.DOMAIN_LOCK != null) {
-            account = contact.getAccount().getJid().getEscapedLocal();
-        } else {
-            account = contact.getAccount().getJid().asBareJid().toEscapedString();
-        }
+        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);
         binding.detailsContactBadge.setOnClickListener(this::onBadgeClick);
@@ -498,7 +492,7 @@ 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.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
+                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());
@@ -510,7 +504,7 @@ public class ContactDetailsActivity extends OmemoActivity implements OnAccountUp
         binding.keysWrapper.setVisibility(hasKeys ? View.VISIBLE : View.GONE);
 
         List<ListItem.Tag> tagList = contact.getTags(this);
-        if (tagList.size() == 0 || !this.showDynamicTags) {
+        if (tagList.isEmpty() || !this.showDynamicTags) {
             binding.tags.setVisibility(View.GONE);
         } else {
             binding.tags.setVisibility(View.VISIBLE);

src/main/java/eu/siacs/conversations/ui/ConversationActivity.java 🔗

@@ -16,10 +16,4 @@ public class ConversationActivity extends AppCompatActivity {
 		startActivity(new Intent(this, ConversationsActivity.class));
 		finish();
 	}
-
-	@Override
-	protected void onResume(){
-		super.onResume();
-		SettingsUtils.applyScreenshotPreventionSetting(this);
-	}
 }

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -22,6 +22,7 @@ import android.content.Intent;
 import android.content.IntentSender.SendIntentException;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -63,6 +64,7 @@ import androidx.core.view.inputmethod.InputConnectionCompat;
 import androidx.core.view.inputmethod.InputContentInfoCompat;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 
@@ -1062,7 +1064,7 @@ public class ConversationFragment extends XmppFragment
                 };
         if (conversation == null
                 || conversation.getMode() == Conversation.MODE_MULTI
-                || Attachment.canBeSendInband(attachments)
+                || Attachment.canBeSendInBand(attachments)
                 || (conversation.getAccount().httpUploadAvailable()
                         && FileBackend.allFilesUnderSize(
                                 getActivity(), attachments, getMaxHttpUploadSize(conversation)))) {
@@ -1934,8 +1936,8 @@ public class ConversationFragment extends XmppFragment
 
     @SuppressLint("InflateParams")
     protected void clearHistoryDialog(final Conversation conversation) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
-        builder.setTitle(getString(R.string.clear_conversation_history));
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
+        builder.setTitle(R.string.clear_conversation_history);
         final View dialogView =
                 requireActivity().getLayoutInflater().inflate(R.layout.dialog_clear_history, null);
         final CheckBox endConversationCheckBox =
@@ -1958,7 +1960,7 @@ public class ConversationFragment extends XmppFragment
     }
 
     protected void muteConversationDialog(final Conversation conversation) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
         builder.setTitle(R.string.disable_notifications);
         final int[] durations = getResources().getIntArray(R.array.mute_options_durations);
         final CharSequence[] labels = new CharSequence[durations.length];
@@ -2132,7 +2134,7 @@ public class ConversationFragment extends XmppFragment
     }
 
     private void showErrorMessage(final Message message) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
         builder.setTitle(R.string.error_message);
         final String errorMessage = message.getErrorMessage();
         final String[] errorMessageParts =
@@ -2159,7 +2161,7 @@ public class ConversationFragment extends XmppFragment
     }
 
     private void deleteFile(final Message message) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
         builder.setNegativeButton(R.string.cancel, null);
         builder.setTitle(R.string.delete_file_dialog);
         builder.setMessage(R.string.delete_file_dialog_msg);
@@ -2921,10 +2923,11 @@ public class ConversationFragment extends XmppFragment
             status = Presence.Status.OFFLINE;
         }
         this.binding.textSendButton.setTag(action);
+        this.binding.textSendButton.setIconResource(SendButtonTool.getSendButtonImageResource(action));
+        this.binding.textSendButton.setIconTint(ColorStateList.valueOf(SendButtonTool.getSendButtonColor(this.binding.textSendButton, status)));
+        // TODO send button color
         final Activity activity = getActivity();
         if (activity != null) {
-            this.binding.textSendButton.setImageResource(
-                    SendButtonTool.getSendButtonImageResource(activity, action, status));
         }
     }
 
@@ -3247,9 +3250,8 @@ public class ConversationFragment extends XmppFragment
                         });
     }
 
-    public void showNoPGPKeyDialog(boolean plural, DialogInterface.OnClickListener listener) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setIconAttribute(android.R.attr.alertDialogIcon);
+    public void showNoPGPKeyDialog(final boolean plural, final DialogInterface.OnClickListener listener) {
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
         if (plural) {
             builder.setTitle(getString(R.string.no_pgp_keys));
             builder.setMessage(getText(R.string.contacts_have_no_pgp_keys));

src/main/java/eu/siacs/conversations/ui/ConversationsActivity.java 🔗

@@ -59,18 +59,18 @@ import androidx.appcompat.app.AlertDialog;
 import androidx.core.app.ActivityCompat;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import org.openintents.openpgp.util.OpenPgpApi;
 
 import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.OmemoSetting;
 import eu.siacs.conversations.databinding.ActivityConversationsBinding;
-import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Conversational;
@@ -80,11 +80,11 @@ import eu.siacs.conversations.ui.interfaces.OnConversationArchived;
 import eu.siacs.conversations.ui.interfaces.OnConversationRead;
 import eu.siacs.conversations.ui.interfaces.OnConversationSelected;
 import eu.siacs.conversations.ui.interfaces.OnConversationsListItemUpdated;
-import eu.siacs.conversations.ui.util.ActionBarUtil;
 import eu.siacs.conversations.ui.util.ActivityResult;
 import eu.siacs.conversations.ui.util.ConversationMenuConfigurator;
 import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
 import eu.siacs.conversations.ui.util.PendingItem;
+import eu.siacs.conversations.ui.util.ToolbarUtils;
 import eu.siacs.conversations.utils.ExceptionHelper;
 import eu.siacs.conversations.utils.SignupUtils;
 import eu.siacs.conversations.utils.XmppUri;
@@ -227,10 +227,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     }
 
     private boolean openBatteryOptimizationDialogIfNeeded() {
-        if (isOptimizingBattery()
-                && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M
-                && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
-            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        if (isOptimizingBattery() && getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true)) {
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
             builder.setTitle(R.string.battery_optimizations_enabled);
             builder.setMessage(getString(R.string.battery_optimizations_enabled_dialog, getString(R.string.app_name)));
             builder.setPositiveButton(R.string.next, (dialog, which) -> {
@@ -372,6 +370,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
         ConversationMenuConfigurator.reloadFeatures(this);
         OmemoSetting.load(this);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_conversations);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
         this.getFragmentManager().addOnBackStackChangedListener(this::invalidateActionBarTitle);
@@ -466,9 +465,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
         conversationFragment.reInit(conversation, extras == null ? new Bundle() : extras);
         if (mainNeedsRefresh) {
             refreshFragment(R.id.main_fragment);
-        } else {
-            invalidateActionBarTitle();
         }
+        invalidateActionBarTitle();
     }
 
     private static void executePendingTransactions(final FragmentManager fragmentManager) {
@@ -546,15 +544,8 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
     }
 
     @Override
-    protected void onStart() {
+    public void onStart() {
         super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            this.mSkipBackgroundBinding = true;
-            recreate();
-        } else {
-            this.mSkipBackgroundBinding = false;
-        }
         mRedirectInProcess.set(false);
     }
 
@@ -630,21 +621,31 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
         }
         final FragmentManager fragmentManager = getFragmentManager();
         final Fragment mainFragment = fragmentManager.findFragmentById(R.id.main_fragment);
-        if (mainFragment instanceof ConversationFragment) {
-            final Conversation conversation = ((ConversationFragment) mainFragment).getConversation();
+        if (mainFragment instanceof ConversationFragment conversationFragment) {
+            final Conversation conversation = conversationFragment.getConversation();
             if (conversation != null) {
                 actionBar.setTitle(conversation.getName());
                 actionBar.setDisplayHomeAsUpEnabled(true);
-                ActionBarUtil.setActionBarOnClickListener(
+                ToolbarUtils.setActionBarOnClickListener(
                         binding.toolbar,
                         (v) -> openConversationDetails(conversation)
                 );
                 return;
             }
         }
-        actionBar.setTitle(R.string.app_name);
+        final Fragment secondaryFragment = fragmentManager.findFragmentById(R.id.secondary_fragment);
+        if (secondaryFragment instanceof ConversationFragment conversationFragment) {
+            final Conversation conversation = conversationFragment.getConversation();
+            if (conversation != null) {
+                actionBar.setTitle(conversation.getName());
+            } else {
+                actionBar.setTitle(R.string.app_name);
+            }
+        } else {
+            actionBar.setTitle(R.string.app_name);
+        }
         actionBar.setDisplayHomeAsUpEnabled(false);
-        ActionBarUtil.resetActionBarOnClickListeners(binding.toolbar);
+        ToolbarUtils.resetActionBarOnClickListeners(binding.toolbar);
     }
 
     private void openConversationDetails(final Conversation conversation) {

src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java 🔗

@@ -50,6 +50,8 @@ import androidx.recyclerview.widget.ItemTouchHelper;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.google.android.material.color.MaterialColors;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.snackbar.Snackbar;
 import com.google.common.collect.Collections2;
 
@@ -72,10 +74,8 @@ import eu.siacs.conversations.ui.util.MenuDoubleTabUtil;
 import eu.siacs.conversations.ui.util.PendingActionHelper;
 import eu.siacs.conversations.ui.util.PendingItem;
 import eu.siacs.conversations.ui.util.ScrollState;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.AccountUtils;
 import eu.siacs.conversations.utils.EasyOnboardingInvite;
-import eu.siacs.conversations.utils.ThemeHelper;
 
 import static androidx.recyclerview.widget.ItemTouchHelper.LEFT;
 import static androidx.recyclerview.widget.ItemTouchHelper.RIGHT;
@@ -111,7 +111,7 @@ public class ConversationsOverviewFragment extends XmppFragment {
 			super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
 			if(actionState != ItemTouchHelper.ACTION_STATE_IDLE){
 				Paint paint = new Paint();
-				paint.setColor(StyledAttributes.getColor(activity,R.attr.conversations_overview_background));
+				paint.setColor(MaterialColors.getColor(viewHolder.itemView, com.google.android.material.R.attr.colorSecondaryFixedDim));
 				paint.setStyle(Paint.Style.FILL);
 				c.drawRect(viewHolder.itemView.getLeft(),viewHolder.itemView.getTop()
 						,viewHolder.itemView.getRight(),viewHolder.itemView.getBottom(), paint);
@@ -196,8 +196,6 @@ public class ConversationsOverviewFragment extends XmppFragment {
 					activity.xmppConnectionService.archiveConversation(c);
 				}
 			});
-
-			ThemeHelper.fix(snackbar);
 			snackbar.show();
 		}
 	};
@@ -381,14 +379,14 @@ public class ConversationsOverviewFragment extends XmppFragment {
 
 	private void selectAccountToStartEasyInvite() {
 		final List<Account> accounts = EasyOnboardingInvite.getSupportingAccounts(activity.xmppConnectionService);
-		if (accounts.size() == 0) {
+		if (accounts.isEmpty()) {
 			//This can technically happen if opening the menu item races with accounts reconnecting or something
 			Toast.makeText(getActivity(),R.string.no_active_accounts_support_this, Toast.LENGTH_LONG).show();
 		} else if (accounts.size() == 1) {
 			openEasyInviteScreen(accounts.get(0));
 		} else {
 			final AtomicReference<Account> selectedAccount = new AtomicReference<>(accounts.get(0));
-			final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity);
+			final MaterialAlertDialogBuilder alertDialogBuilder = new MaterialAlertDialogBuilder(activity);
 			alertDialogBuilder.setTitle(R.string.choose_account);
 			final String[] asStrings = Collections2.transform(accounts, a -> a.getJid().asBareJid().toEscapedString()).toArray(new String[0]);
 			alertDialogBuilder.setSingleChoiceItems(asStrings, 0, (dialog, which) -> selectedAccount.set(accounts.get(which)));

src/main/java/eu/siacs/conversations/ui/CreatePrivateGroupChatDialog.java 🔗

@@ -3,18 +3,20 @@ package eu.siacs.conversations.ui;
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Bundle;
-import android.widget.Spinner;
+import android.widget.AutoCompleteTextView;
 
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.AlertDialog;
 import androidx.databinding.DataBindingUtil;
 import androidx.fragment.app.DialogFragment;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import java.util.ArrayList;
 import java.util.List;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.CreateConferenceDialogBinding;
+import eu.siacs.conversations.databinding.DialogCreateConferenceBinding;
 import eu.siacs.conversations.ui.util.DelayedHintHelper;
 
 public class CreatePrivateGroupChatDialog extends DialogFragment {
@@ -39,9 +41,9 @@ public class CreatePrivateGroupChatDialog extends DialogFragment {
     @NonNull
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
         builder.setTitle(R.string.create_private_group_chat);
-        CreateConferenceDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_conference_dialog, null, false);
+        final DialogCreateConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_create_conference, null, false);
         ArrayList<String> mActivatedAccounts = getArguments().getStringArrayList(ACCOUNTS_LIST_KEY);
         StartConversationActivity.populateAccountSpinner(getActivity(), mActivatedAccounts, binding.account);
         builder.setView(binding.getRoot());
@@ -57,7 +59,7 @@ public class CreatePrivateGroupChatDialog extends DialogFragment {
 
 
     public interface CreateConferenceDialogListener {
-        void onCreateDialogPositiveClick(Spinner spinner, String subject);
+        void onCreateDialogPositiveClick(AutoCompleteTextView spinner, String subject);
     }
 
     @Override

src/main/java/eu/siacs/conversations/ui/CreatePublicChannelDialog.java 🔗

@@ -17,13 +17,14 @@ import androidx.appcompat.app.AlertDialog;
 import androidx.databinding.DataBindingUtil;
 import androidx.fragment.app.DialogFragment;
 
-import java.security.SecureRandom;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.CreatePublicChannelDialogBinding;
+import eu.siacs.conversations.databinding.DialogCreatePublicChannelBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
@@ -44,7 +45,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
     private boolean nameEntered = false;
     private boolean skipTetxWatcher = false;
 
-    public static CreatePublicChannelDialog newInstance(List<String> accounts) {
+    public static CreatePublicChannelDialog newInstance(final List<String> accounts) {
         CreatePublicChannelDialog dialog = new CreatePublicChannelDialog();
         Bundle bundle = new Bundle();
         bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList<String>) accounts);
@@ -63,9 +64,9 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         jidWasModified = savedInstanceState != null && savedInstanceState.getBoolean("jid_was_modified_false", false);
         nameEntered = savedInstanceState != null && savedInstanceState.getBoolean("name_entered", false);
-        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
         builder.setTitle(R.string.create_public_channel);
-        final CreatePublicChannelDialogBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.create_public_channel_dialog, null, false);
+        final DialogCreatePublicChannelBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_create_public_channel, null, false);
         binding.account.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
             @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@@ -107,7 +108,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
         builder.setPositiveButton(nameEntered ? R.string.create : R.string.next, null);
         builder.setNegativeButton(nameEntered ? R.string.back : R.string.cancel, null);
         DelayedHintHelper.setHint(R.string.channel_bare_jid_example, binding.jid);
-        this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
+        this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
         binding.jid.setAdapter(knownHostsAdapter);
         final AlertDialog dialog = builder.create();
         binding.groupChatName.setOnEditorActionListener((v, actionId, event) -> {
@@ -121,7 +122,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
         return dialog;
     }
 
-    private void updateJidSuggestion(CreatePublicChannelDialogBinding binding) {
+    private void updateJidSuggestion(final DialogCreatePublicChannelBinding binding) {
         if (jidWasModified) {
             return;
         }
@@ -138,7 +139,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
         super.onSaveInstanceState(outState);
     }
 
-    private static String getJidSuggestion(CreatePublicChannelDialogBinding binding) {
+    private static String getJidSuggestion(final DialogCreatePublicChannelBinding binding) {
         final Account account = StartConversationActivity.getSelectedAccount(binding.getRoot().getContext(), binding.account);
         final XmppConnection connection = account == null ? null : account.getXmppConnection();
         if (connection == null) {
@@ -169,7 +170,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
         return name.replaceAll("\\s+","-");
     }
 
-    private void goBack(AlertDialog dialog, CreatePublicChannelDialogBinding binding) {
+    private void goBack(AlertDialog dialog, DialogCreatePublicChannelBinding binding) {
         if (nameEntered) {
             nameEntered = false;
             updateInputs(binding, true);
@@ -179,7 +180,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
         }
     }
 
-    private void submit(AlertDialog dialog, CreatePublicChannelDialogBinding binding) {
+    private void submit(AlertDialog dialog, DialogCreatePublicChannelBinding binding) {
         final Context context = binding.getRoot().getContext();
         final Editable nameText = binding.groupChatName.getText();
         final String name = nameText == null ? "" : nameText.toString().trim();
@@ -227,7 +228,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
     }
 
 
-    private void updateInputs(CreatePublicChannelDialogBinding binding, boolean requestFocus) {
+    private void updateInputs(final DialogCreatePublicChannelBinding binding, final boolean requestFocus) {
         binding.xmppAddressLayout.setVisibility(nameEntered ? View.VISIBLE : View.GONE);
         binding.nameLayout.setVisibility(nameEntered ? View.GONE : View.VISIBLE);
         if (!requestFocus) {
@@ -265,7 +266,7 @@ public class CreatePublicChannelDialog extends DialogFragment implements OnBacke
     }
 
     @Override
-    public void onAttach(Context context) {
+    public void onAttach(@NonNull Context context) {
         super.onAttach(context);
         try {
             mListener = (CreatePublicChannelDialogListener) context;

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -33,9 +33,10 @@ import android.widget.Toast;
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AlertDialog.Builder;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.color.MaterialColors;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.textfield.TextInputLayout;
 import com.google.common.base.CharMatcher;
 
@@ -98,7 +99,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     private Jid jidToEdit;
     private boolean mInitMode = false;
     private Boolean mForceRegister = null;
-    private boolean mUsernameMode = Config.DOMAIN_LOCK != null;
+    private boolean mUsernameMode = false;
     private boolean mShowOptions = false;
     private Account mAccount;
     private final OnClickListener mCancelButtonClickListener = v -> {
@@ -609,6 +610,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             this.mSavedInstanceInit = savedInstanceState.getBoolean("initMode", false);
         }
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_edit_account);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         binding.accountJid.addTextChangedListener(this.mTextWatcher);
         binding.accountJid.setOnFocusChangeListener(this.mEditTextFocusListener);
@@ -697,13 +699,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     @Override
-    protected void onStart() {
+    public void onStart() {
         super.onStart();
         final Intent intent = getIntent();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        } else if (intent != null) {
+        if (intent != null) {
             try {
                 this.jidToEdit = Jid.ofEscaped(intent.getStringExtra("jid"));
             } catch (final IllegalArgumentException | NullPointerException ignored) {
@@ -758,7 +757,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     private void displayVerificationWarningDialog(final XmppUri xmppUri) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setTitle(R.string.verify_omemo_keys);
         View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
         final CheckBox isTrustedSource = view.findViewById(R.id.trusted_source);
@@ -773,7 +772,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             }
         });
         builder.setNegativeButton(R.string.cancel, (dialog, which) -> finish());
-        AlertDialog dialog = builder.create();
+        final var dialog = builder.create();
         dialog.setCanceledOnTouchOutside(false);
         dialog.setOnCancelListener(d -> finish());
         dialog.show();
@@ -835,7 +834,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             this.binding.accountJidLayout.setHint(getString(R.string.username_hint));
         } else {
             final KnownHostsAdapter mKnownHostsAdapter = new KnownHostsAdapter(this,
-                    R.layout.simple_list_item,
+                    R.layout.item_autocomplete,
                     xmppConnectionService.getKnownHosts());
             this.binding.accountJid.setAdapter(mKnownHostsAdapter);
         }
@@ -853,7 +852,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         if (mAccount != null && mAccount.getJid().getDomain() != null) {
             return mAccount.getServer();
         } else {
-            return Config.DOMAIN_LOCK;
+            return null;
         }
     }
 
@@ -940,7 +939,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     private void changePresence() {
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
         boolean manualStatus = sharedPreferences.getBoolean(SettingsActivity.MANUALLY_CHANGE_PRESENCE, getResources().getBoolean(R.bool.manually_change_presence));
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         final DialogPresenceBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_presence, null, false);
         String current = mAccount.getPresenceStatusMessage();
         if (current != null && !current.trim().isEmpty()) {
@@ -949,7 +948,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
         setAvailabilityRadioButton(mAccount.getPresenceStatus(), binding);
         binding.show.setVisibility(manualStatus ? View.VISIBLE : View.GONE);
         List<PresenceTemplate> templates = xmppConnectionService.getPresenceTemplates(mAccount);
-        PresenceTemplateAdapter presenceTemplateAdapter = new PresenceTemplateAdapter(this, R.layout.simple_list_item, templates);
+        PresenceTemplateAdapter presenceTemplateAdapter = new PresenceTemplateAdapter(this, R.layout.item_autocomplete, templates);
         binding.statusMessage.setAdapter(presenceTemplateAdapter);
         binding.statusMessage.setOnItemClickListener((parent, view, position, id) -> {
             PresenceTemplate template = (PresenceTemplate) parent.getItemAtPosition(position);
@@ -1144,7 +1143,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                 this.binding.pgpFingerprint.setText(OpenPgpUtils.convertKeyIdToHex(pgpKeyId));
                 this.binding.pgpFingerprint.setOnClickListener(openPgp);
                 if ("pgp".equals(messageFingerprint)) {
-                    this.binding.pgpFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
+                    this.binding.pgpFingerprintDesc.setTextColor(MaterialColors.getColor(binding.pgpFingerprintDesc, com.google.android.material.R.attr.colorPrimaryVariant));
                 }
                 this.binding.pgpFingerprintDesc.setOnClickListener(openPgp);
                 this.binding.actionDeletePgp.setOnClickListener(delete);
@@ -1155,10 +1154,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             if (ownAxolotlFingerprint != null && Config.supportOmemo()) {
                 this.binding.axolotlFingerprintBox.setVisibility(View.VISIBLE);
                 if (ownAxolotlFingerprint.equals(messageFingerprint)) {
-                    this.binding.ownFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption_Highlight);
+                    this.binding.ownFingerprintDesc.setTextColor(MaterialColors.getColor(binding.ownFingerprintDesc, com.google.android.material.R.attr.colorPrimaryVariant));
                     this.binding.ownFingerprintDesc.setText(R.string.omemo_fingerprint_selected_message);
                 } else {
-                    this.binding.ownFingerprintDesc.setTextAppearance(this, R.style.TextAppearance_Conversations_Caption);
+                    this.binding.ownFingerprintDesc.setTextColor(MaterialColors.getColor(binding.ownFingerprintDesc, com.google.android.material.R.attr.colorOnSurface));
                     this.binding.ownFingerprintDesc.setText(R.string.omemo_fingerprint);
                 }
                 this.binding.axolotlFingerprint.setText(CryptoHelper.prettifyFingerprint(ownAxolotlFingerprint.substring(2)));
@@ -1222,10 +1221,10 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     private void updateDisplayName(String displayName) {
         if (TextUtils.isEmpty(displayName)) {
             this.binding.yourName.setText(R.string.no_name_set_instructions);
-            this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1_Tertiary);
+            this.binding.yourName.setTextColor(MaterialColors.getColor(binding.yourName, com.google.android.material.R.attr.colorOnSurfaceVariant));
         } else {
             this.binding.yourName.setText(displayName);
-            this.binding.yourName.setTextAppearance(this, R.style.TextAppearance_Conversations_Body1);
+            this.binding.yourName.setTextColor(MaterialColors.getColor(binding.yourName, com.google.android.material.R.attr.colorOnSurfaceVariant));
         }
     }
 
@@ -1249,7 +1248,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     private void showDeletePgpDialog() {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setTitle(R.string.unpublish_pgp);
         builder.setMessage(R.string.unpublish_pgp_message);
         builder.setNegativeButton(R.string.cancel, null);
@@ -1279,7 +1278,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
                     Toast.makeText(EditAccountActivity.this, getString(R.string.device_does_not_support_data_saver, getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
                 }
             });
-        } else if (showBatteryWarning && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+        } else if (showBatteryWarning) {
             this.binding.osOptimizationDisable.setText(R.string.disable);
             this.binding.osOptimizationHeadline.setText(R.string.battery_optimizations_enabled);
             this.binding.osOptimizationBody.setText(getString(R.string.battery_optimizations_enabled_explained, getString(R.string.app_name)));
@@ -1297,7 +1296,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
     }
 
     public void showWipePepDialog() {
-        Builder builder = new Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setTitle(getString(R.string.clear_other_devices));
         builder.setIconAttribute(android.R.attr.alertDialogIcon);
         builder.setMessage(getString(R.string.clear_other_devices_desc));
@@ -1324,7 +1323,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             if (mCaptchaDialog != null && mCaptchaDialog.isShowing()) {
                 mCaptchaDialog.dismiss();
             }
-            final Builder builder = new Builder(EditAccountActivity.this);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(EditAccountActivity.this);
             final View view = getLayoutInflater().inflate(R.layout.captcha, null);
             final ImageView imageView = view.findViewById(R.id.captcha);
             final EditText input = view.findViewById(R.id.input);
@@ -1372,7 +1371,7 @@ public class EditAccountActivity extends OmemoActivity implements OnAccountUpdat
             if (mFetchingMamPrefsToast != null) {
                 mFetchingMamPrefsToast.cancel();
             }
-            Builder builder = new Builder(EditAccountActivity.this);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(EditAccountActivity.this);
             builder.setTitle(R.string.server_side_mam_prefs);
             String defaultAttr = prefs.getAttribute("default");
             final List<String> defaults = Arrays.asList("never", "roster", "always");

src/main/java/eu/siacs/conversations/ui/EnterJidDialog.java 🔗

@@ -13,15 +13,17 @@ import androidx.appcompat.app.AlertDialog;
 import androidx.databinding.DataBindingUtil;
 import androidx.fragment.app.DialogFragment;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import com.google.common.base.Strings;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
-import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.EnterJidDialogBinding;
+import eu.siacs.conversations.databinding.DialogEnterJidBinding;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
 import eu.siacs.conversations.ui.interfaces.OnBackendConnected;
@@ -46,28 +48,28 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
     private KnownHostsAdapter knownHostsAdapter;
     private Collection<String> whitelistedDomains = Collections.emptyList();
 
-    private EnterJidDialogBinding binding;
+    private DialogEnterJidBinding binding;
     private AlertDialog dialog;
     private boolean sanityCheckJid = false;
 
     private boolean issuedWarning = false;
 
     public static EnterJidDialog newInstance(
-            final List<String> activatedAccounts,
+            final ArrayList<String> activatedAccounts,
             final String title,
             final String positiveButton,
             final String prefilledJid,
             final String account,
             boolean allowEditJid,
             final boolean sanity_check_jid) {
-        EnterJidDialog dialog = new EnterJidDialog();
+        final EnterJidDialog dialog = new EnterJidDialog();
         Bundle bundle = new Bundle();
         bundle.putString(TITLE_KEY, title);
         bundle.putString(POSITIVE_BUTTON_KEY, positiveButton);
         bundle.putString(PREFILLED_JID_KEY, prefilledJid);
         bundle.putString(ACCOUNT_KEY, account);
         bundle.putBoolean(ALLOW_EDIT_JID_KEY, allowEditJid);
-        bundle.putStringArrayList(ACCOUNTS_LIST_KEY, (ArrayList<String>) activatedAccounts);
+        bundle.putStringArrayList(ACCOUNTS_LIST_KEY, activatedAccounts);
         bundle.putBoolean(SANITY_CHECK_JID, sanity_check_jid);
         dialog.setArguments(bundle);
         return dialog;
@@ -91,16 +93,16 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
 
     @NonNull
     @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        builder.setTitle(getArguments().getString(TITLE_KEY));
+    public Dialog onCreateDialog(final Bundle savedInstanceState) {
+        final var arguments = getArguments();
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
+        builder.setTitle(arguments.getString(TITLE_KEY));
         binding =
-                DataBindingUtil.inflate(
-                        getActivity().getLayoutInflater(), R.layout.enter_jid_dialog, null, false);
-        this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
+                DataBindingUtil.inflate(requireActivity().getLayoutInflater(), R.layout.dialog_enter_jid, null, false);
+        this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
         binding.jid.setAdapter(this.knownHostsAdapter);
         binding.jid.addTextChangedListener(this);
-        String prefilledJid = getArguments().getString(PREFILLED_JID_KEY);
+        final String prefilledJid = arguments.getString(PREFILLED_JID_KEY);
         if (prefilledJid != null) {
             binding.jid.append(prefilledJid);
             if (!getArguments().getBoolean(ALLOW_EDIT_JID_KEY)) {
@@ -114,18 +116,18 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
 
         DelayedHintHelper.setHint(R.string.account_settings_example_jabber_id, binding.jid);
 
-        String account = getArguments().getString(ACCOUNT_KEY);
-        if (account == null) {
+        final String account = getArguments().getString(ACCOUNT_KEY);
+        if (Strings.isNullOrEmpty(account)) {
             StartConversationActivity.populateAccountSpinner(
                     getActivity(),
-                    getArguments().getStringArrayList(ACCOUNTS_LIST_KEY),
+                    arguments.getStringArrayList(ACCOUNTS_LIST_KEY),
                     binding.account);
         } else {
-            ArrayAdapter<String> adapter =
-                    new ArrayAdapter<>(
-                            getActivity(), R.layout.simple_list_item, new String[] {account});
+            final ArrayAdapter<String> adapter =
+                    new ArrayAdapter<>(requireActivity(), R.layout.item_autocomplete, new String[] {account});
+            binding.account.setText(account);
             binding.account.setEnabled(false);
-            adapter.setDropDownViewResource(R.layout.simple_list_item);
+            adapter.setDropDownViewResource(R.layout.item_autocomplete);
             binding.account.setAdapter(adapter);
         }
 
@@ -135,9 +137,7 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
         this.dialog = builder.create();
 
         View.OnClickListener dialogOnClick =
-                v -> {
-                    handleEnter(binding, account);
-                };
+                v -> handleEnter(binding, account);
 
         binding.jid.setOnEditorActionListener(
                 (v, actionId, event) -> {
@@ -150,21 +150,13 @@ public class EnterJidDialog extends DialogFragment implements OnBackendConnected
         return dialog;
     }
 
-    private void handleEnter(EnterJidDialogBinding binding, String account) {
+    private void handleEnter(DialogEnterJidBinding binding, String account) {
         final Jid accountJid;
         if (!binding.account.isEnabled() && account == null) {
             return;
         }
         try {
-            if (Config.DOMAIN_LOCK != null) {
-                accountJid =
-                        Jid.ofEscaped(
-                                (String) binding.account.getSelectedItem(),
-                                Config.DOMAIN_LOCK,
-                                null);
-            } else {
-                accountJid = Jid.ofEscaped((String) binding.account.getSelectedItem());
-            }
+                accountJid = Jid.ofEscaped((String) binding.account.getEditableText().toString());
         } catch (final IllegalArgumentException e) {
             return;
         }

src/main/java/eu/siacs/conversations/ui/JoinConferenceDialog.java 🔗

@@ -13,6 +13,7 @@ import androidx.appcompat.app.AlertDialog;
 import androidx.databinding.DataBindingUtil;
 import androidx.fragment.app.DialogFragment;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.textfield.TextInputLayout;
 
 import java.util.ArrayList;
@@ -50,11 +51,11 @@ public class JoinConferenceDialog extends DialogFragment implements OnBackendCon
 	@NonNull
 	@Override
 	public Dialog onCreateDialog(Bundle savedInstanceState) {
-		final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+		final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity());
 		builder.setTitle(R.string.join_public_channel);
-		DialogJoinConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_join_conference, null, false);
+		final DialogJoinConferenceBinding binding = DataBindingUtil.inflate(getActivity().getLayoutInflater(), R.layout.dialog_join_conference, null, false);
 		DelayedHintHelper.setHint(R.string.channel_full_jid_example, binding.jid);
-		this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.simple_list_item);
+		this.knownHostsAdapter = new KnownHostsAdapter(getActivity(), R.layout.item_autocomplete);
 		binding.jid.setAdapter(knownHostsAdapter);
 		String prefilledJid = getArguments().getString(PREFILLED_JID_KEY);
 		if (prefilledJid != null) {
@@ -117,6 +118,6 @@ public class JoinConferenceDialog extends DialogFragment implements OnBackendCon
 	}
 
 	public interface JoinConferenceDialogListener {
-		void onJoinDialogPositiveClick(Dialog dialog, Spinner spinner, TextInputLayout jidLayout, AutoCompleteTextView jid, boolean isBookmarkChecked);
+		void onJoinDialogPositiveClick(Dialog dialog, AutoCompleteTextView spinner, TextInputLayout jidLayout, AutoCompleteTextView jid, boolean isBookmarkChecked);
 	}
 }

src/main/java/eu/siacs/conversations/ui/LocationActivity.java 🔗

@@ -40,7 +40,6 @@ import eu.siacs.conversations.ui.util.LocationHelper;
 import eu.siacs.conversations.ui.widget.Marker;
 import eu.siacs.conversations.ui.widget.MyLocation;
 import eu.siacs.conversations.ui.util.SettingsUtils;
-import eu.siacs.conversations.utils.ThemeHelper;
 
 public abstract class LocationActivity extends ActionBarActivity implements LocationListener {
 	protected LocationManager locationManager;
@@ -78,7 +77,6 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
 	protected void onCreate(final Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		final Context ctx = getApplicationContext();
-		setTheme(ThemeHelper.find(this));
 
 		final PackageManager packageManager = ctx.getPackageManager();
 		hasLocationFeature = packageManager.hasSystemFeature(PackageManager.FEATURE_LOCATION) ||
@@ -90,7 +88,7 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
 		// Ask for location permissions if location services are enabled and we're
 		// just starting the activity (we don't want to keep pestering them on every
 		// screen rotation or if there's no point because it's disabled anyways).
-		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && savedInstanceState == null) {
+		if (savedInstanceState == null) {
 			requestPermissions(REQUEST_CODE_CREATE);
 		}
 
@@ -224,7 +222,6 @@ public abstract class LocationActivity extends ActionBarActivity implements Loca
 	@Override
 	protected void onResume() {
 		super.onResume();
-		SettingsUtils.applyScreenshotPreventionSetting(this);
 		Configuration.getInstance().load(this, getPreferences());
 		map.onResume();
 		this.setMyLoc(null);

src/main/java/eu/siacs/conversations/ui/MediaBrowserActivity.java 🔗

@@ -29,6 +29,7 @@ public class MediaBrowserActivity extends XmppActivity implements OnMediaLoaded
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         this.binding = DataBindingUtil.setContentView(this,R.layout.activity_media_browser);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
         mMediaAdapter = new MediaAdapter(this, R.dimen.media_size);

src/main/java/eu/siacs/conversations/ui/MemorizingActivity.java 🔗

@@ -33,6 +33,8 @@ import android.os.Bundle;
 import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.app.AppCompatActivity;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -40,7 +42,6 @@ import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.MTMDecision;
 import eu.siacs.conversations.services.MemorizingTrustManager;
 import eu.siacs.conversations.ui.util.SettingsUtils;
-import eu.siacs.conversations.utils.ThemeHelper;
 
 public class MemorizingActivity extends AppCompatActivity implements OnClickListener, OnCancelListener {
 
@@ -53,10 +54,7 @@ public class MemorizingActivity extends AppCompatActivity implements OnClickList
 	@Override
 	public void onCreate(Bundle savedInstanceState) {
 		LOGGER.log(Level.FINE, "onCreate");
-		setTheme(ThemeHelper.find(this));
 		super.onCreate(savedInstanceState);
-		getLayoutInflater().inflate(R.layout.toolbar, findViewById(android.R.id.content));
-		setSupportActionBar(findViewById(R.id.toolbar));
 	}
 
 	@Override
@@ -69,7 +67,7 @@ public class MemorizingActivity extends AppCompatActivity implements OnClickList
 		int titleId = i.getIntExtra(MemorizingTrustManager.DECISION_TITLE_ID, R.string.mtm_accept_cert);
 		String cert = i.getStringExtra(MemorizingTrustManager.DECISION_INTENT_CERT);
 		LOGGER.log(Level.FINE, "onResume with " + i.getExtras() + " decId=" + decisionId + " data: " + i.getData());
-		dialog = new AlertDialog.Builder(this).setTitle(titleId)
+		dialog = new MaterialAlertDialogBuilder(this).setTitle(titleId)
 			.setMessage(cert)
 			.setPositiveButton(R.string.always, this)
 			.setNeutralButton(R.string.once, this)

src/main/java/eu/siacs/conversations/ui/MucUsersActivity.java 🔗

@@ -102,8 +102,9 @@ public class MucUsersActivity extends XmppActivity implements XmppConnectionServ
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users);
+        final ActivityMucUsersBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_muc_users);
         setSupportActionBar(binding.toolbar);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         configureActionBar(getSupportActionBar(), true);
         this.userAdapter = new UserAdapter(getPreferences().getBoolean("advanced_muc_mode", false));
         binding.list.setAdapter(this.userAdapter);

src/main/java/eu/siacs/conversations/ui/OmemoActivity.java 🔗

@@ -11,6 +11,9 @@ import android.widget.Toast;
 import androidx.appcompat.app.AlertDialog;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.color.MaterialColors;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
@@ -33,10 +36,7 @@ public abstract class OmemoActivity extends XmppActivity {
 		Object account = v.getTag(R.id.TAG_ACCOUNT);
 		Object fingerprint = v.getTag(R.id.TAG_FINGERPRINT);
 		Object fingerprintStatus = v.getTag(R.id.TAG_FINGERPRINT_STATUS);
-		if (account != null
-				&& fingerprint != null
-				&& account instanceof Account
-				&& fingerprintStatus != null
+		if (account instanceof Account
 				&& fingerprint instanceof String
 				&& fingerprintStatus instanceof FingerprintStatus) {
 			getMenuInflater().inflate(R.menu.omemo_key_context, menu);
@@ -130,8 +130,8 @@ public abstract class OmemoActivity extends XmppActivity {
 		binding.tglTrust.setChecked(status.isTrusted());
 
 		if (status.isActive()) {
-			binding.key.setTextAppearance(this,R.style.TextAppearance_Conversations_Fingerprint);
-			binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption);
+			binding.key.setTextColor(MaterialColors.getColor(binding.key, com.google.android.material.R.attr.colorOnSurface));
+			binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorOnSurface));
 			if (status.isVerified()) {
 				binding.verifiedFingerprint.setVisibility(View.VISIBLE);
 				binding.verifiedFingerprint.setAlpha(1.0f);
@@ -157,8 +157,8 @@ public abstract class OmemoActivity extends XmppActivity {
 				toast = v -> hideToast();
 			}
 		} else {
-			binding.key.setTextAppearance(this,R.style.TextAppearance_Conversations_Fingerprint_Disabled);
-			binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption_Disabled);
+			binding.key.setTextColor(MaterialColors.getColor(binding.key, com.google.android.material.R.attr.colorOnSurfaceVariant));
+			binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorOnSurfaceVariant));
 			toast = v -> replaceToast(getString(R.string.this_device_is_no_longer_in_use), false);
 			if (status.isVerified()) {
 				binding.tglTrust.setVisibility(View.GONE);
@@ -181,7 +181,7 @@ public abstract class OmemoActivity extends XmppActivity {
 			binding.keyType.setVisibility(View.GONE);
 		}
 		if (highlight) {
-			binding.keyType.setTextAppearance(this,R.style.TextAppearance_Conversations_Caption_Highlight);
+			binding.keyType.setTextColor(MaterialColors.getColor(binding.keyType, com.google.android.material.R.attr.colorPrimaryVariant));
 			binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message));
 		} else {
 			binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
@@ -191,7 +191,7 @@ public abstract class OmemoActivity extends XmppActivity {
 	}
 
 	public void showPurgeKeyDialog(final Account account, final String fingerprint) {
-		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
 		builder.setTitle(R.string.distrust_omemo_key);
 		builder.setMessage(R.string.distrust_omemo_key_text);
 		builder.setNegativeButton(getString(R.string.cancel), null);

src/main/java/eu/siacs/conversations/ui/PublishGroupChatProfilePictureActivity.java 🔗

@@ -91,6 +91,7 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(this.binding.toolbar);
         configureActionBar(getSupportActionBar());
         this.binding.cancelButton.setOnClickListener((v) -> this.finish());
@@ -114,6 +115,7 @@ public class PublishGroupChatProfilePictureActivity extends XmppActivity impleme
 
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
         if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
             final CropImage.ActivityResult result = CropImage.getActivityResult(data);
             if (resultCode == RESULT_OK) {

src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java 🔗

@@ -18,6 +18,7 @@ import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.StringRes;
+import androidx.databinding.DataBindingUtil;
 
 import com.canhub.cropper.CropImage;
 
@@ -25,6 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityPublishProfilePictureBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.interfaces.OnAvatarPublication;
@@ -77,7 +79,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
     public void onAvatarPublicationFailed(int res) {
         runOnUiThread(() -> {
             hintOrWarning.setText(res);
-            hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
             hintOrWarning.setVisibility(View.VISIBLE);
             publishing = false;
             togglePublishButton(true, R.string.publish);
@@ -87,8 +88,12 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_publish_profile_picture);
-        setSupportActionBar(findViewById(R.id.toolbar));
+
+        ActivityPublishProfilePictureBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_publish_profile_picture);
+
+        setSupportActionBar(binding.toolbar);
+
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
 
         this.avatar = findViewById(R.id.account_image);
         this.cancelButton = findViewById(R.id.cancel_button);
@@ -220,7 +225,7 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
     }
 
     @Override
-    protected void onStart() {
+    public void onStart() {
         super.onStart();
         final Intent intent = getIntent();
         this.mInitialAccountSetup = intent != null && intent.getBooleanExtra("setup", false);
@@ -261,7 +266,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
         if (bm == null) {
             togglePublishButton(false, R.string.publish);
             this.hintOrWarning.setVisibility(View.VISIBLE);
-            this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
             this.hintOrWarning.setText(R.string.error_publish_avatar_converting);
             return;
         }
@@ -272,7 +276,6 @@ public class PublishProfilePictureActivity extends XmppActivity implements XmppC
         } else {
             togglePublishButton(false, R.string.publish);
             this.hintOrWarning.setVisibility(View.VISIBLE);
-            this.hintOrWarning.setTextAppearance(this,R.style.TextAppearance_Conversations_Body1_Warning);
             if (account.getStatus() == Account.State.ONLINE) {
                 this.hintOrWarning.setText(R.string.error_publish_avatar_no_server_support);
             } else {

src/main/java/eu/siacs/conversations/ui/RecordingActivity.java 🔗

@@ -15,6 +15,7 @@ import android.view.View;
 import android.view.WindowManager;
 import android.widget.Toast;
 
+import androidx.appcompat.app.AppCompatActivity;
 import androidx.databinding.DataBindingUtil;
 
 import com.google.common.collect.ImmutableSet;
@@ -33,10 +34,9 @@ import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.ActivityRecordingBinding;
 import eu.siacs.conversations.ui.util.SettingsUtils;
-import eu.siacs.conversations.utils.ThemeHelper;
 import eu.siacs.conversations.utils.TimeFrameUtils;
 
-public class RecordingActivity extends Activity implements View.OnClickListener {
+public class RecordingActivity extends BaseActivity implements View.OnClickListener {
 
     private ActivityRecordingBinding binding;
 
@@ -61,7 +61,6 @@ public class RecordingActivity extends Activity implements View.OnClickListener
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        setTheme(ThemeHelper.findDialog(this));
         super.onCreate(savedInstanceState);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_recording);
         this.binding.cancelButton.setOnClickListener(this);
@@ -69,19 +68,13 @@ public class RecordingActivity extends Activity implements View.OnClickListener
         this.setFinishOnTouchOutside(false);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
     }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        SettingsUtils.applyScreenshotPreventionSetting(this);
-    }
-
     @Override
-    protected void onStart() {
+    public void onStart() {
         super.onStart();
         if (!startRecording()) {
             this.binding.shareButton.setEnabled(false);
-            this.binding.timer.setTextAppearance(this, R.style.TextAppearance_Conversations_Title);
+            this.binding.timer.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium);
+            // TODO reset font family. make red?
             this.binding.timer.setText(R.string.unable_to_start_recording);
         }
     }

src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java 🔗

@@ -179,6 +179,7 @@ public class RtpSessionActivity extends XmppActivity
                                 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_rtp_session);
         setSupportActionBar(binding.toolbar);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
     }
 
     @Override
@@ -920,34 +921,34 @@ public class RtpSessionActivity extends XmppActivity
         } else if (state == RtpEndUserState.INCOMING_CALL) {
             this.binding.rejectCall.setContentDescription(getString(R.string.dismiss_call));
             this.binding.rejectCall.setOnClickListener(this::rejectCall);
-            this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_white_48dp);
+            this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_24dp);
             this.binding.rejectCall.setVisibility(View.VISIBLE);
             this.binding.endCall.setVisibility(View.INVISIBLE);
             this.binding.acceptCall.setContentDescription(getString(R.string.answer_call));
             this.binding.acceptCall.setOnClickListener(this::acceptCall);
-            this.binding.acceptCall.setImageResource(R.drawable.ic_call_white_48dp);
+            this.binding.acceptCall.setImageResource(R.drawable.ic_call_24dp);
             this.binding.acceptCall.setVisibility(View.VISIBLE);
         } else if (state == RtpEndUserState.INCOMING_CONTENT_ADD) {
             this.binding.rejectCall.setContentDescription(
                     getString(R.string.reject_switch_to_video));
             this.binding.rejectCall.setOnClickListener(this::rejectContentAdd);
-            this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
+            this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
             this.binding.rejectCall.setVisibility(View.VISIBLE);
             this.binding.endCall.setVisibility(View.INVISIBLE);
             this.binding.acceptCall.setContentDescription(getString(R.string.accept));
             this.binding.acceptCall.setOnClickListener((v -> acceptContentAdd(contentAddition)));
-            this.binding.acceptCall.setImageResource(R.drawable.ic_baseline_check_24);
+            this.binding.acceptCall.setImageResource(R.drawable.ic_check_24dp);
             this.binding.acceptCall.setVisibility(View.VISIBLE);
         } else if (asList(RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.CONTACT_OFFLINE)
                 .contains(state)) {
             this.binding.rejectCall.setContentDescription(getString(R.string.exit));
             this.binding.rejectCall.setOnClickListener(this::exit);
-            this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
+            this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
             this.binding.rejectCall.setVisibility(View.VISIBLE);
             this.binding.endCall.setVisibility(View.INVISIBLE);
             this.binding.acceptCall.setContentDescription(getString(R.string.record_voice_mail));
             this.binding.acceptCall.setOnClickListener(this::recordVoiceMail);
-            this.binding.acceptCall.setImageResource(R.drawable.ic_voicemail_white_24dp);
+            this.binding.acceptCall.setImageResource(R.drawable.ic_voicemail_24dp);
             this.binding.acceptCall.setVisibility(View.VISIBLE);
         } else if (asList(
                         RtpEndUserState.CONNECTIVITY_ERROR,
@@ -958,18 +959,18 @@ public class RtpSessionActivity extends XmppActivity
                 .contains(state)) {
             this.binding.rejectCall.setContentDescription(getString(R.string.exit));
             this.binding.rejectCall.setOnClickListener(this::exit);
-            this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
+            this.binding.rejectCall.setImageResource(R.drawable.ic_clear_24dp);
             this.binding.rejectCall.setVisibility(View.VISIBLE);
             this.binding.endCall.setVisibility(View.INVISIBLE);
             this.binding.acceptCall.setContentDescription(getString(R.string.try_again));
             this.binding.acceptCall.setOnClickListener(this::retry);
-            this.binding.acceptCall.setImageResource(R.drawable.ic_replay_white_48dp);
+            this.binding.acceptCall.setImageResource(R.drawable.ic_replay_24dp);
             this.binding.acceptCall.setVisibility(View.VISIBLE);
         } else {
             this.binding.rejectCall.setVisibility(View.INVISIBLE);
             this.binding.endCall.setContentDescription(getString(R.string.hang_up));
             this.binding.endCall.setOnClickListener(this::endCall);
-            this.binding.endCall.setImageResource(R.drawable.ic_call_end_white_48dp);
+            this.binding.endCall.setImageResource(R.drawable.ic_call_end_24dp);
             this.binding.endCall.setVisibility(View.VISIBLE);
             this.binding.acceptCall.setVisibility(View.INVISIBLE);
         }
@@ -1038,7 +1039,7 @@ public class RtpSessionActivity extends XmppActivity
         switch (selectedAudioDevice) {
             case EARPIECE -> {
                 this.binding.inCallActionRight.setImageResource(
-                        R.drawable.ic_volume_off_black_24dp);
+                        R.drawable.ic_volume_off_24dp);
                 if (numberOfChoices >= 2) {
                     this.binding.inCallActionRight.setOnClickListener(this::switchToSpeaker);
                 } else {
@@ -1047,12 +1048,12 @@ public class RtpSessionActivity extends XmppActivity
                 }
             }
             case WIRED_HEADSET -> {
-                this.binding.inCallActionRight.setImageResource(R.drawable.ic_headset_black_24dp);
+                this.binding.inCallActionRight.setImageResource(R.drawable.ic_headset_mic_24dp);
                 this.binding.inCallActionRight.setOnClickListener(null);
                 this.binding.inCallActionRight.setClickable(false);
             }
             case SPEAKER_PHONE -> {
-                this.binding.inCallActionRight.setImageResource(R.drawable.ic_volume_up_black_24dp);
+                this.binding.inCallActionRight.setImageResource(R.drawable.ic_volume_up_24dp);
                 if (numberOfChoices >= 2) {
                     this.binding.inCallActionRight.setOnClickListener(this::switchToEarpiece);
                 } else {
@@ -1062,7 +1063,7 @@ public class RtpSessionActivity extends XmppActivity
             }
             case BLUETOOTH -> {
                 this.binding.inCallActionRight.setImageResource(
-                        R.drawable.ic_bluetooth_audio_black_24dp);
+                        R.drawable.ic_bluetooth_audio_24dp);
                 this.binding.inCallActionRight.setOnClickListener(null);
                 this.binding.inCallActionRight.setClickable(false);
             }
@@ -1076,17 +1077,17 @@ public class RtpSessionActivity extends XmppActivity
         this.binding.inCallActionRight.setVisibility(View.VISIBLE);
         if (isCameraSwitchable) {
             this.binding.inCallActionFarRight.setImageResource(
-                    R.drawable.ic_flip_camera_android_black_24dp);
+                    R.drawable.ic_flip_camera_android_24dp);
             this.binding.inCallActionFarRight.setVisibility(View.VISIBLE);
             this.binding.inCallActionFarRight.setOnClickListener(this::switchCamera);
         } else {
             this.binding.inCallActionFarRight.setVisibility(View.GONE);
         }
         if (videoEnabled) {
-            this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_black_24dp);
+            this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_24dp);
             this.binding.inCallActionRight.setOnClickListener(this::disableVideo);
         } else {
-            this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_off_black_24dp);
+            this.binding.inCallActionRight.setImageResource(R.drawable.ic_videocam_off_24dp);
             this.binding.inCallActionRight.setOnClickListener(this::enableVideo);
         }
     }
@@ -1140,10 +1141,10 @@ public class RtpSessionActivity extends XmppActivity
     @SuppressLint("RestrictedApi")
     private void updateInCallButtonConfigurationMicrophone(final boolean microphoneEnabled) {
         if (microphoneEnabled) {
-            this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_black_24dp);
+            this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_24dp);
             this.binding.inCallActionLeft.setOnClickListener(this::disableMicrophone);
         } else {
-            this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_off_black_24dp);
+            this.binding.inCallActionLeft.setImageResource(R.drawable.ic_mic_off_24dp);
             this.binding.inCallActionLeft.setOnClickListener(this::enableMicrophone);
         }
         this.binding.inCallActionLeft.setVisibility(View.VISIBLE);

src/main/java/eu/siacs/conversations/ui/SearchActivity.java 🔗

@@ -42,8 +42,10 @@ import android.view.View;
 import android.widget.AdapterView;
 import android.widget.EditText;
 
+import androidx.core.content.ContextCompat;
 import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.color.MaterialColors;
 import com.google.common.base.Strings;
 
 import java.lang.ref.WeakReference;
@@ -64,7 +66,6 @@ import eu.siacs.conversations.ui.util.DateSeparator;
 import eu.siacs.conversations.ui.util.ListViewUtils;
 import eu.siacs.conversations.ui.util.PendingItem;
 import eu.siacs.conversations.ui.util.ShareUtil;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.FtsUtils;
 import eu.siacs.conversations.utils.MessageUtils;
 
@@ -95,6 +96,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
 		}
 		super.onCreate(bundle);
 		this.binding = DataBindingUtil.setContentView(this, R.layout.activity_search);
+		Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
 		setSupportActionBar(this.binding.toolbar);
 		configureActionBar(getSupportActionBar());
 		this.messageListAdapter = new MessageAdapter(this, this.messages, uuid == null);
@@ -223,12 +225,12 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
 	private void changeBackground(boolean hasSearch, boolean hasResults) {
 		if (hasSearch) {
 			if (hasResults) {
-				binding.searchResults.setBackgroundColor(StyledAttributes.getColor(this, R.attr.color_background_secondary));
+				binding.searchResults.setBackgroundColor(MaterialColors.getColor(binding.searchResults, com.google.android.material.R.attr.colorSurface));
 			} else {
-				binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_no_results));
+				binding.searchResults.setBackgroundResource(R.drawable.background_no_results);
 			}
 		} else {
-			binding.searchResults.setBackground(StyledAttributes.getDrawable(this, R.attr.activity_background_search));
+			binding.searchResults.setBackgroundResource(R.drawable.background_search);
 		}
 	}
 
@@ -248,14 +250,14 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
 		if (!currentSearch.watch(term)) {
 			return;
 		}
-		if (term.size() > 0) {
-			xmppConnectionService.search(term, uuid,this);
-		} else {
+		if (term.isEmpty()) {
 			MessageSearchTask.cancelRunningTasks();
 			this.messages.clear();
 			messageListAdapter.setHighlightedTerm(null);
 			messageListAdapter.notifyDataSetChanged();
 			changeBackground(false, false);
+		} else {
+			xmppConnectionService.search(term, uuid,this);
 		}
 	}
 
@@ -267,7 +269,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
 			DateSeparator.addAll(messages);
 			this.messages.addAll(messages);
 			messageListAdapter.notifyDataSetChanged();
-			changeBackground(true, messages.size() > 0);
+			changeBackground(true, !messages.isEmpty());
 			ListViewUtils.scrollToBottom(this.binding.searchResults);
 		});
 	}

src/main/java/eu/siacs/conversations/ui/SettingsActivity.java 🔗

@@ -22,7 +22,10 @@ import android.widget.Toast;
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.AlertDialog;
 import androidx.core.content.ContextCompat;
+import androidx.databinding.DataBindingUtil;
 
+import com.google.android.material.color.DynamicColors;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -37,8 +40,10 @@ import java.util.Collections;
 import java.util.List;
 
 import eu.siacs.conversations.Config;
+import eu.siacs.conversations.Conversations;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.OmemoSetting;
+import eu.siacs.conversations.databinding.ActivitySettingsBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.services.ExportBackupService;
@@ -46,10 +51,8 @@ import eu.siacs.conversations.services.MemorizingTrustManager;
 import eu.siacs.conversations.services.QuickConversationsService;
 import eu.siacs.conversations.services.UnifiedPushDistributor;
 import eu.siacs.conversations.ui.util.SettingsUtils;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.GeoHelper;
 import eu.siacs.conversations.utils.TimeFrameUtils;
-import eu.siacs.conversations.xmpp.InvalidJid;
 import eu.siacs.conversations.xmpp.Jid;
 
 public class SettingsActivity extends XmppActivity implements OnSharedPreferenceChangeListener {
@@ -74,7 +77,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_settings);
+        final ActivitySettingsBinding binding = DataBindingUtil.setContentView(this,R.layout.activity_settings);
         FragmentManager fm = getFragmentManager();
         mSettingsFragment = (SettingsFragment) fm.findFragmentById(R.id.settings_content);
         if (mSettingsFragment == null
@@ -83,13 +86,8 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
             fm.beginTransaction().replace(R.id.settings_content, mSettingsFragment).commit();
         }
         mSettingsFragment.setActivityIntent(getIntent());
-        this.mTheme = findTheme();
-        setTheme(this.mTheme);
-        getWindow()
-                .getDecorView()
-                .setBackgroundColor(
-                        StyledAttributes.getColor(this, R.attr.color_background_primary));
-        setSupportActionBar(findViewById(R.id.toolbar));
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+        setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
     }
 
@@ -185,6 +183,12 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
             }
         }
 
+        final PreferenceCategory uiPreferenceCategory = (PreferenceCategory) mSettingsFragment.findPreference("ui");
+        final Preference dynamicColorsPreference = mSettingsFragment.findPreference("dynamic_colors");
+        if (dynamicColorsPreference != null && !DynamicColors.isDynamicColorAvailable()) {
+            uiPreferenceCategory.removePreference(dynamicColorsPreference);
+        }
+
         ListPreference automaticMessageDeletionList =
                 (ListPreference) mSettingsFragment.findPreference(AUTOMATIC_MESSAGE_DELETION);
         if (automaticMessageDeletionList != null) {
@@ -204,36 +208,6 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
             automaticMessageDeletionList.setEntryValues(entryValues);
         }
 
-        boolean removeLocation =
-                new Intent("eu.siacs.conversations.location.request")
-                                .resolveActivity(getPackageManager())
-                        == null;
-        boolean removeVoice =
-                new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
-                                .resolveActivity(getPackageManager())
-                        == null;
-
-        ListPreference quickAction =
-                (ListPreference) mSettingsFragment.findPreference("quick_action");
-        if (quickAction != null && (removeLocation || removeVoice)) {
-            ArrayList<CharSequence> entries =
-                    new ArrayList<>(Arrays.asList(quickAction.getEntries()));
-            ArrayList<CharSequence> entryValues =
-                    new ArrayList<>(Arrays.asList(quickAction.getEntryValues()));
-            int index = entryValues.indexOf("location");
-            if (index > 0 && removeLocation) {
-                entries.remove(index);
-                entryValues.remove(index);
-            }
-            index = entryValues.indexOf("voice");
-            if (index > 0 && removeVoice) {
-                entries.remove(index);
-                entryValues.remove(index);
-            }
-            quickAction.setEntries(entries.toArray(new CharSequence[entries.size()]));
-            quickAction.setEntryValues(entryValues.toArray(new CharSequence[entryValues.size()]));
-        }
-
         final Preference removeCertsPreference =
                 mSettingsFragment.findPreference("remove_trusted_certificates");
         if (removeCertsPreference != null) {
@@ -242,17 +216,16 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
                         final MemorizingTrustManager mtm =
                                 xmppConnectionService.getMemorizingTrustManager();
                         final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
-                        if (aliases.size() == 0) {
+                        if (aliases.isEmpty()) {
                             displayToast(getString(R.string.toast_no_trusted_certs));
                             return true;
                         }
                         final ArrayList<Integer> selectedItems = new ArrayList<>();
-                        final AlertDialog.Builder dialogBuilder =
-                                new AlertDialog.Builder(SettingsActivity.this);
+                        final MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(SettingsActivity.this);
                         dialogBuilder.setTitle(
                                 getResources().getString(R.string.dialog_manage_certs_title));
                         dialogBuilder.setMultiChoiceItems(
-                                aliases.toArray(new CharSequence[aliases.size()]),
+                                aliases.toArray(new CharSequence[0]),
                                 null,
                                 (dialog, indexSelected, isChecked) -> {
                                     if (isChecked) {
@@ -262,7 +235,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
                                     }
                                     ((AlertDialog) dialog)
                                             .getButton(DialogInterface.BUTTON_POSITIVE)
-                                            .setEnabled(selectedItems.size() > 0);
+                                            .setEnabled(!selectedItems.isEmpty());
                                 });
 
                         dialogBuilder.setPositiveButton(
@@ -273,13 +246,12 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
                                     if (count > 0) {
                                         for (int i = 0; i < count; i++) {
                                             try {
-                                                Integer item =
-                                                        Integer.valueOf(
+                                                final int item =
+                                                        Integer.parseInt(
                                                                 selectedItems.get(i).toString());
                                                 String alias = aliases.get(item);
                                                 mtm.deleteCertificate(alias);
-                                            } catch (KeyStoreException e) {
-                                                e.printStackTrace();
+                                            } catch (final KeyStoreException e) {
                                                 displayToast("Error: " + e.getLocalizedMessage());
                                             }
                                         }
@@ -372,10 +344,8 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
 
     private boolean isCallable(final Intent i) {
         return i != null
-                && getPackageManager()
-                                .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY)
-                                .size()
-                        > 0;
+                && !getPackageManager()
+                .queryIntentActivities(i, PackageManager.MATCH_DEFAULT_ONLY).isEmpty();
     }
 
     private boolean cleanCache() {
@@ -413,7 +383,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
     }
 
     private boolean deleteOmemoIdentities() {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setTitle(R.string.pref_delete_omemo_identities);
         final List<CharSequence> accounts = new ArrayList<>();
         for (Account account : xmppConnectionService.getAccounts()) {
@@ -502,10 +472,12 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
         } else if (name.equals(AUTOMATIC_MESSAGE_DELETION)) {
             xmppConnectionService.expireOldMessages(true);
         } else if (name.equals(THEME)) {
-            final int theme = findTheme();
-            if (this.mTheme != theme) {
-                recreate();
-            }
+            final var value = preferences.getString(THEME,getString(R.string.theme));
+            final int desiredNightMode = Conversations.getDesiredNightMode(value);
+            setDesiredNightMode(desiredNightMode);
+        } else if (name.equals("dynamic_colors")) {
+            final var value = preferences.getBoolean("dynamic_colors",false);
+            setDynamicColors(value);
         } else if (name.equals(PREVENT_SCREENSHOTS)) {
             SettingsUtils.applyScreenshotPreventionSetting(this);
         } else if (UnifiedPushDistributor.PREFERENCES.contains(name)) {
@@ -572,7 +544,7 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
 
     private void createBackup() {
         ContextCompat.startForegroundService(this, new Intent(this, ExportBackupService.class));
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setMessage(R.string.backup_started_message);
         builder.setPositiveButton(R.string.ok, null);
         builder.create().show();

src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java 🔗

@@ -5,7 +5,6 @@ import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.location.Location;
 import android.location.LocationListener;
-import android.os.Build;
 import android.os.Bundle;
 import android.view.View;
 
@@ -15,11 +14,6 @@ import androidx.databinding.DataBindingUtil;
 import com.google.android.material.snackbar.Snackbar;
 import com.google.common.math.DoubleMath;
 
-import org.osmdroid.api.IGeoPoint;
-import org.osmdroid.util.GeoPoint;
-
-import java.math.RoundingMode;
-
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.databinding.ActivityShareLocationBinding;
@@ -27,7 +21,11 @@ import eu.siacs.conversations.ui.util.LocationHelper;
 import eu.siacs.conversations.ui.widget.Marker;
 import eu.siacs.conversations.ui.widget.MyLocation;
 import eu.siacs.conversations.utils.LocationProvider;
-import eu.siacs.conversations.utils.ThemeHelper;
+
+import org.osmdroid.api.IGeoPoint;
+import org.osmdroid.util.GeoPoint;
+
+import java.math.RoundingMode;
 
 public class ShareLocationActivity extends LocationActivity implements LocationListener {
 
@@ -58,6 +56,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
         super.onCreate(savedInstanceState);
 
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_share_location);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
         setupMapView(binding.map, LocationProvider.getGeoPoint(this));
@@ -71,13 +70,12 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
         this.snackBar.setAction(R.string.enable, view -> {
             if (isLocationEnabledAndAllowed()) {
                 updateUi();
-            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !hasLocationPermissions()) {
+            } else if (!hasLocationPermissions()) {
                 requestPermissions(REQUEST_CODE_SNACKBAR_PRESSED);
             } else if (!isLocationEnabled()) {
                 startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
             }
         });
-        ThemeHelper.fix(this.snackBar);
 
         this.binding.shareButton.setOnClickListener(this::shareLocation);
 
@@ -87,7 +85,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
             if (!marker_fixed_to_loc) {
                 if (!isLocationEnabled()) {
                     startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
-                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                } else {
                     requestPermissions(REQUEST_CODE_FAB_PRESSED);
                 }
             }
@@ -117,16 +115,9 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
                                            @NonNull final int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 
-        if (grantResults.length > 0 &&
-                grantResults[0] != PackageManager.PERMISSION_GRANTED &&
-                Build.VERSION.SDK_INT >= 23 &&
-                permissions.length > 0 &&
-                (
-                        Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) ||
-                                Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) ||
-                                Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0])
-                ) &&
-                !shouldShowRequestPermissionRationale(permissions[0])) {
+        if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED && permissions.length > 0 && (
+                Manifest.permission.LOCATION_HARDWARE.equals(permissions[0]) || Manifest.permission.ACCESS_FINE_LOCATION.equals(permissions[0]) || Manifest.permission.ACCESS_COARSE_LOCATION.equals(permissions[0])
+        ) && !shouldShowRequestPermissionRationale(permissions[0])) {
             noAskAgain = true;
         }
 
@@ -172,7 +163,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
     }
 
     @Override
-    public void onLocationChanged(final Location location) {
+    public void onLocationChanged(@NonNull final Location location) {
         if (this.myLoc == null) {
             this.marker_fixed_to_loc = true;
         }
@@ -206,7 +197,7 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
     }
 
     private boolean isLocationEnabledAndAllowed() {
-        return this.hasLocationFeature && (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || this.hasLocationPermissions()) && this.isLocationEnabled();
+        return this.hasLocationFeature && this.hasLocationPermissions() && this.isLocationEnabled();
     }
 
     private void toggleFixedLocation() {
@@ -229,8 +220,8 @@ public class ShareLocationActivity extends LocationActivity implements LocationL
         if (isLocationEnabledAndAllowed()) {
             this.binding.fab.setVisibility(View.VISIBLE);
             runOnUiThread(() -> {
-                this.binding.fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_white_24dp :
-                        R.drawable.ic_gps_not_fixed_white_24dp);
+                this.binding.fab.setImageResource(marker_fixed_to_loc ? R.drawable.ic_gps_fixed_24dp :
+                        R.drawable.ic_gps_not_fixed_24dp);
                 this.binding.fab.setContentDescription(getResources().getString(
                         marker_fixed_to_loc ? R.string.action_unfix_from_location : R.string.action_fix_to_location
                 ));

src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java 🔗

@@ -9,21 +9,24 @@ import android.view.Menu;
 import android.view.MenuItem;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+import androidx.databinding.DataBindingUtil;
 import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.ArrayList;
-import java.util.List;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityShareWithBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.adapter.ConversationAdapter;
 import eu.siacs.conversations.xmpp.Jid;
 
-public class ShareWithActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
+import java.util.ArrayList;
+import java.util.List;
+
+public class ShareWithActivity extends XmppActivity
+        implements XmppConnectionService.OnConversationUpdate {
 
     private static final int REQUEST_STORAGE_PERMISSION = 0x733f32;
     private Conversation mPendingConversation = null;
@@ -48,11 +51,10 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
     private ConversationAdapter mAdapter;
     private final List<Conversation> mConversations = new ArrayList<>();
 
-
-    protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
+    protected void onActivityResult(
+            final int requestCode, final int resultCode, final Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-        if (requestCode == REQUEST_START_NEW_CONVERSATION
-                && resultCode == RESULT_OK) {
+        if (requestCode == REQUEST_START_NEW_CONVERSATION && resultCode == RESULT_OK) {
             share.contact = data.getStringExtra("contact");
             share.account = data.getStringExtra(EXTRA_ACCOUNT);
         }
@@ -65,7 +67,10 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
     }
 
     @Override
-    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+    public void onRequestPermissionsResult(
+            final int requestCode,
+            @NonNull final String[] permissions,
+            @NonNull final int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         if (grantResults.length > 0)
             if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
@@ -77,27 +82,35 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
                     }
                 }
             } else {
-                Toast.makeText(this, getString(R.string.no_storage_permission, getString(R.string.app_name)), Toast.LENGTH_SHORT).show();
+                Toast.makeText(
+                                this,
+                                getString(
+                                        R.string.no_storage_permission,
+                                        getString(R.string.app_name)),
+                                Toast.LENGTH_SHORT)
+                        .show();
             }
     }
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_share_with);
 
-        setSupportActionBar(findViewById(R.id.toolbar));
-        if (getSupportActionBar() != null) {
-            getSupportActionBar().setDisplayHomeAsUpEnabled(false);
-            getSupportActionBar().setHomeButtonEnabled(false);
+        final ActivityShareWithBinding binding =
+                DataBindingUtil.setContentView(this, R.layout.activity_share_with);
+        setSupportActionBar(binding.toolbar);
+        final var actionBar = getSupportActionBar();
+        if (actionBar != null) {
+            actionBar.setDisplayHomeAsUpEnabled(false);
+            actionBar.setHomeButtonEnabled(false);
         }
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+        setTitle(R.string.title_activity_share_with);
 
-        setTitle(getString(R.string.title_activity_sharewith));
-
-        RecyclerView mListView = findViewById(R.id.choose_conversation_list);
         mAdapter = new ConversationAdapter(this, this.mConversations);
-        mListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
-        mListView.setAdapter(mAdapter);
+        binding.chooseConversationList.setLayoutManager(
+                new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
+        binding.chooseConversationList.setAdapter(mAdapter);
         mAdapter.setConversationClickListener((view, conversation) -> share(conversation));
         this.share = new Share();
     }
@@ -112,8 +125,9 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
     public boolean onOptionsItemSelected(final MenuItem item) {
         switch (item.getItemId()) {
             case R.id.action_add:
-                final Intent intent = new Intent(getApplicationContext(), ChooseContactActivity.class);
-                intent.putExtra("direct_search",true);
+                final Intent intent =
+                        new Intent(getApplicationContext(), ChooseContactActivity.class);
+                intent.putExtra("direct_search", true);
                 startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION);
                 return true;
         }
@@ -133,7 +147,8 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
         if (Intent.ACTION_SEND.equals(action)) {
             final String text = intent.getStringExtra(Intent.EXTRA_TEXT);
             final Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
-            final boolean asQuote = intent.getBooleanExtra(ConversationsActivity.EXTRA_AS_QUOTE, false);
+            final boolean asQuote =
+                    intent.getBooleanExtra(ConversationsActivity.EXTRA_AS_QUOTE, false);
 
             if (data != null && "geo".equals(data.getScheme())) {
                 this.share.uris.clear();
@@ -151,14 +166,16 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
             this.share.uris = uris == null ? new ArrayList<>() : uris;
         }
         if (xmppConnectionServiceBound) {
-            xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0, false);
+            xmppConnectionService.populateWithOrderedConversations(
+                    mConversations, this.share.uris.isEmpty(), false);
         }
-
     }
 
     @Override
     void onBackendConnected() {
-        if (xmppConnectionServiceBound && share != null && ((share.contact != null && share.account != null))) {
+        if (xmppConnectionServiceBound
+                && share != null
+                && ((share.contact != null && share.account != null))) {
             share();
             return;
         }
@@ -167,32 +184,34 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
 
     private void share() {
         final Conversation conversation;
-            Account account;
-            try {
-                account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
-            } catch (final IllegalArgumentException e) {
-                account = null;
-            }
-            if (account == null) {
-                return;
-            }
+        Account account;
+        try {
+            account = xmppConnectionService.findAccountByJid(Jid.ofEscaped(share.account));
+        } catch (final IllegalArgumentException e) {
+            account = null;
+        }
+        if (account == null) {
+            return;
+        }
 
-            try {
-                conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), false, true);
-            } catch (final IllegalArgumentException e) {
-                return;
-            }
+        try {
+            conversation =
+                    xmppConnectionService.findOrCreateConversation(
+                            account, Jid.of(share.contact), false, true);
+        } catch (final IllegalArgumentException e) {
+            return;
+        }
         share(conversation);
     }
 
     private void share(final Conversation conversation) {
-        if (share.uris.size() != 0 && !hasStoragePermission(REQUEST_STORAGE_PERMISSION)) {
+        if (!share.uris.isEmpty() && !hasStoragePermission(REQUEST_STORAGE_PERMISSION)) {
             mPendingConversation = conversation;
             return;
         }
-        Intent intent = new Intent(this, ConversationsActivity.class);
+        final Intent intent = new Intent(this, ConversationsActivity.class);
         intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());
-        if (share.uris.size() > 0) {
+        if (!share.uris.isEmpty()) {
             intent.setAction(Intent.ACTION_SEND_MULTIPLE);
             intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, share.uris);
             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -207,15 +226,20 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
         try {
             startActivity(intent);
         } catch (SecurityException e) {
-            Toast.makeText(this, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show();
+            Toast.makeText(
+                            this,
+                            R.string.sharing_application_not_grant_permission,
+                            Toast.LENGTH_SHORT)
+                    .show();
             return;
         }
         finish();
     }
 
     public void refreshUiReal() {
-        //TODO inject desired order to not resort on refresh
-        xmppConnectionService.populateWithOrderedConversations(mConversations, this.share != null && this.share.uris.size() == 0, false);
+        // TODO inject desired order to not resort on refresh
+        xmppConnectionService.populateWithOrderedConversations(
+                mConversations, this.share != null && this.share.uris.isEmpty(), false);
         mAdapter.notifyDataSetChanged();
     }
 }

src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java 🔗

@@ -49,6 +49,8 @@ public class ShowLocationActivity extends LocationActivity implements LocationLi
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_show_location);
         setSupportActionBar(binding.toolbar);
 
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
+
         configureActionBar(getSupportActionBar());
         setupMapView(this.binding.map, this.loc);
 

src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java 🔗

@@ -6,7 +6,6 @@ import android.app.Dialog;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
@@ -55,7 +54,10 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 import androidx.viewpager.widget.PagerAdapter;
 import androidx.viewpager.widget.ViewPager;
 
+import com.google.android.material.color.MaterialColors;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.textfield.TextInputLayout;
+import com.google.common.collect.Iterables;
 import com.leinardi.android.speeddial.SpeedDialActionItem;
 import com.leinardi.android.speeddial.SpeedDialView;
 
@@ -109,7 +111,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
     private ListItemAdapter mContactsAdapter;
     private final List<ListItem> conferences = new ArrayList<>();
     private ListItemAdapter mConferenceAdapter;
-    private final List<String> mActivatedAccounts = new ArrayList<>();
+    private final ArrayList<String> mActivatedAccounts = new ArrayList<>();
     private EditText mSearchEditText;
     private final AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false);
     private final AtomicBoolean mOpenedFab = new AtomicBoolean(false);
@@ -220,19 +222,20 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
         }
     };
 
-    public static void populateAccountSpinner(Context context, List<String> accounts, Spinner spinner) {
-        if (accounts.size() > 0) {
-            ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.simple_list_item, accounts);
-            adapter.setDropDownViewResource(R.layout.simple_list_item);
-            spinner.setAdapter(adapter);
-            spinner.setEnabled(true);
-        } else {
+    public static void populateAccountSpinner(final Context context, final List<String> accounts, final AutoCompleteTextView spinner) {
+        if (accounts.isEmpty()) {
             ArrayAdapter<String> adapter = new ArrayAdapter<>(context,
-                    R.layout.simple_list_item,
+                    R.layout.item_autocomplete,
                     Collections.singletonList(context.getString(R.string.no_accounts)));
-            adapter.setDropDownViewResource(R.layout.simple_list_item);
+            adapter.setDropDownViewResource(R.layout.item_autocomplete);
             spinner.setAdapter(adapter);
             spinner.setEnabled(false);
+        } else {
+            final ArrayAdapter<String> adapter = new ArrayAdapter<>(context, R.layout.item_autocomplete, accounts);
+            adapter.setDropDownViewResource(R.layout.item_autocomplete);
+            spinner.setAdapter(adapter);
+            spinner.setEnabled(true);
+            spinner.setText(Iterables.getFirst(accounts,null),false);
         }
     }
 
@@ -273,6 +276,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         this.binding = DataBindingUtil.setContentView(this, R.layout.activity_start_conversation);
+        Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
         setSupportActionBar(binding.toolbar);
         configureActionBar(getSupportActionBar());
 
@@ -363,7 +367,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
             }
             final SpeedDialActionItem actionItem = new SpeedDialActionItem.Builder(menuItem.getItemId(), menuItem.getIcon())
                     .setLabel(menuItem.getTitle() != null ? menuItem.getTitle().toString() : null)
-                    .setFabImageTintColor(ContextCompat.getColor(this, R.color.white))
+                    .setFabImageTintColor(MaterialColors.getColor(speedDialView, com.google.android.material.R.attr.colorOnSurface))
+                    .setFabBackgroundColor(MaterialColors.getColor(speedDialView, com.google.android.material.R.attr.colorSurfaceContainerHighest))
                     .create();
             speedDialView.addActionItem(actionItem);
         }
@@ -394,13 +399,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
     @Override
     public void onStart() {
         super.onStart();
-        final int theme = findTheme();
-        if (this.mTheme != theme) {
-            recreate();
-        } else {
-            if (pendingViewIntent.peek() == null) {
-                askForContactsPermissions();
-            }
+        if (pendingViewIntent.peek() == null) {
+            askForContactsPermissions();
         }
         mConferenceAdapter.refreshSettings();
         mContactsAdapter.refreshSettings();
@@ -490,7 +490,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
     protected void deleteContact() {
         final int position = contact_context_id;
         final Contact contact = (Contact) contacts.get(position);
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setNegativeButton(R.string.cancel, null);
         builder.setTitle(R.string.action_delete_contact);
         builder.setMessage(JidDialog.style(this, R.string.remove_contact_text, contact.getJid().toEscapedString()));
@@ -506,7 +506,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
         final Bookmark bookmark = (Bookmark) conferences.get(position);
         final var conversation = bookmark.getConversation();
         final boolean hasConversation = conversation != null;
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setNegativeButton(R.string.cancel, null);
         builder.setTitle(R.string.delete_bookmark);
         if (hasConversation) {
@@ -611,18 +611,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
         dialog.show(ft, FRAGMENT_TAG_DIALOG);
     }
 
-    public static Account getSelectedAccount(Context context, Spinner spinner) {
+    public static Account getSelectedAccount(final Context context, final AutoCompleteTextView spinner) {
         if (spinner == null || !spinner.isEnabled()) {
             return null;
         }
         if (context instanceof XmppActivity) {
-            Jid jid;
+            final Jid jid;
             try {
-                if (Config.DOMAIN_LOCK != null) {
-                    jid = Jid.ofEscaped((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null);
-                } else {
-                    jid = Jid.ofEscaped((String) spinner.getSelectedItem());
-                }
+                jid = Jid.ofEscaped(spinner.getText().toString());
             } catch (final IllegalArgumentException e) {
                 return null;
             }
@@ -792,7 +788,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
                     if (requiresConsent
                             || shouldShowRequestPermissionRationale(
                                     Manifest.permission.READ_CONTACTS)) {
-                        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
                         final AtomicBoolean requestPermission = new AtomicBoolean(false);
                         if (QuickConversationsService.isQuicksy()) {
                             builder.setTitle(R.string.quicksy_wants_your_consent);
@@ -1007,7 +1003,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
     }
 
     private void displayVerificationWarningDialog(final Contact contact, final Invite invite) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setTitle(R.string.verify_omemo_keys);
         View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
         final CheckBox isTrustedSource = view.findViewById(R.id.trusted_source);
@@ -1104,7 +1100,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
     }
 
     @Override
-    public void onCreateDialogPositiveClick(Spinner spinner, String name) {
+    public void onCreateDialogPositiveClick(AutoCompleteTextView spinner, String name) {
         if (!xmppConnectionServiceBound) {
             return;
         }
@@ -1122,7 +1118,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
     }
 
     @Override
-    public void onJoinDialogPositiveClick(Dialog dialog, Spinner spinner, TextInputLayout layout, AutoCompleteTextView jid, boolean isBookmarkChecked) {
+    public void onJoinDialogPositiveClick(Dialog dialog, AutoCompleteTextView spinner, TextInputLayout layout, AutoCompleteTextView jid, boolean isBookmarkChecked) {
         if (!xmppConnectionServiceBound) {
             return;
         }

src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java 🔗

@@ -14,14 +14,7 @@ import android.widget.Toast;
 import androidx.appcompat.app.ActionBar;
 import androidx.databinding.DataBindingUtil;
 
-import org.whispersystems.libsignal.IdentityKey;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
@@ -40,6 +33,14 @@ import eu.siacs.conversations.utils.XmppUri;
 import eu.siacs.conversations.xmpp.Jid;
 import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
 
+import org.whispersystems.libsignal.IdentityKey;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdated {
 	private final Map<String, Boolean> ownKeysToTrust = new HashMap<>();
@@ -70,12 +71,14 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 	protected void onCreate(final Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		this.binding = DataBindingUtil.setContentView(this, R.layout.activity_trust_keys);
+		Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
 		this.contactJids = new ArrayList<>();
-		for (String jid : getIntent().getStringArrayExtra("contacts")) {
+		final var intent = getIntent();
+		final String[] contacts = intent == null ? null : intent.getStringArrayExtra("contacts");
+		for (final String jid : (contacts == null ? new String[0] : contacts)) {
 			try {
 				this.contactJids.add(Jid.of(jid));
-			} catch (IllegalArgumentException e) {
-				e.printStackTrace();
+			} catch (final IllegalArgumentException ignored) {
 			}
 		}
 
@@ -100,7 +103,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 	public boolean onCreateOptionsMenu(Menu menu) {
 		getMenuInflater().inflate(R.menu.trust_keys, menu);
 		MenuItem scanQrCode = menu.findItem(R.id.action_scan_qr_code);
-		scanQrCode.setVisible((ownKeysToTrust.size() > 0 || foreignActuallyHasKeys()) && isCameraFeatureAvailable());
+		scanQrCode.setVisible((!ownKeysToTrust.isEmpty() || foreignActuallyHasKeys()) && isCameraFeatureAvailable());
 		return super.onCreateOptionsMenu(menu);
 	}
 
@@ -191,7 +194,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 							}
 					);
 				}
-				if (fingerprints.size() == 0) {
+				if (fingerprints.isEmpty()) {
 					keysCardBinding.noKeysToAccept.setVisibility(View.VISIBLE);
 					if (hasNoOtherTrustedKeys(jid)) {
 						if (!mAccount.getRoster().getContact(jid).mutualPresenceSubscription()) {
@@ -254,8 +257,8 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 		}
 	}
 
-	private void disableEncryptionDialog(View view) {
-		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+	private void disableEncryptionDialog(final View view) {
+		final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
 		builder.setTitle(R.string.disable_encryption);
 		builder.setMessage(R.string.disable_encryption_message);
 		builder.setPositiveButton(R.string.disable_now, (dialog, which) -> {
@@ -279,7 +282,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 	private boolean foreignActuallyHasKeys() {
 		synchronized (this.foreignKeysToTrust) {
 			for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) {
-				if (entry.getValue().size() > 0) {
+				if (!entry.getValue().isEmpty()) {
 					return true;
 				}
 			}
@@ -305,7 +308,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 			foreignKeysToTrust.clear();
 			for (Jid jid : contactJids) {
 				Set<IdentityKey> foreignKeysSet = service.getKeysWithTrust(FingerprintStatus.createActiveUndecided(), jid);
-				if (hasNoOtherTrustedKeys(jid) && ownKeysSet.size() == 0) {
+				if (hasNoOtherTrustedKeys(jid) && ownKeysSet.isEmpty()) {
 					foreignKeysSet.addAll(service.getKeysWithTrust(FingerprintStatus.createActive(false), jid));
 				}
 				Map<String, Boolean> foreignFingerprints = new HashMap<>();
@@ -315,7 +318,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 						foreignFingerprints.put(fingerprint, false);
 					}
 				}
-				if (foreignFingerprints.size() > 0 || !acceptedTargets.contains(jid)) {
+				if (!foreignFingerprints.isEmpty() || !acceptedTargets.contains(jid)) {
 					foreignKeysToTrust.put(jid, foreignFingerprints);
 				}
 			}

src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java 🔗

@@ -42,7 +42,7 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class UriHandlerActivity extends AppCompatActivity {
+public class UriHandlerActivity extends BaseActivity {
 
     public static final String ACTION_SCAN_QR_CODE = "scan_qr_code";
     private static final String EXTRA_ALLOW_PROVISIONING = "extra_allow_provisioning";

src/main/java/eu/siacs/conversations/ui/XmppActivity.java 🔗

@@ -2,7 +2,6 @@ package eu.siacs.conversations.ui;
 
 import android.Manifest;
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.ClipData;
@@ -17,10 +16,10 @@ import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -50,10 +49,11 @@ import androidx.annotation.BoolRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.StringRes;
 import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AlertDialog.Builder;
 import androidx.appcompat.app.AppCompatDelegate;
 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 eu.siacs.conversations.BuildConfig;
@@ -80,7 +80,6 @@ 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.utils.ThemeHelper;
 import eu.siacs.conversations.xmpp.Jid;
 import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
 import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
@@ -106,7 +105,6 @@ public abstract class XmppActivity extends ActionBarActivity {
 
     private boolean isCameraFeatureAvailable = false;
 
-    protected int mTheme;
     protected boolean mUsingEnterKey = false;
     protected boolean mUseTor = false;
     protected Toast mToast;
@@ -154,7 +152,6 @@ public abstract class XmppActivity extends ActionBarActivity {
 
         }
     };
-    public boolean mSkipBackgroundBinding = false;
 
     public static boolean cancelPotentialWork(Message message, ImageView imageView) {
         final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
@@ -212,14 +209,10 @@ public abstract class XmppActivity extends ActionBarActivity {
     abstract protected void refreshUiReal();
 
     @Override
-    protected void onStart() {
+    public void onStart() {
         super.onStart();
         if (!xmppConnectionServiceBound) {
-            if (this.mSkipBackgroundBinding) {
-                Log.d(Config.LOGTAG, "skipping background binding");
-            } else {
-                connectToBackend();
-            }
+            connectToBackend();
         } else {
             this.registerListeners();
             this.onBackendConnected();
@@ -255,7 +248,7 @@ public abstract class XmppActivity extends ActionBarActivity {
     }
 
     public void showInstallPgpDialog() {
-        Builder builder = new AlertDialog.Builder(this);
+        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))));
@@ -298,7 +291,7 @@ public abstract class XmppActivity extends ActionBarActivity {
     }
 
     protected void deleteAccount(final Account account, final Runnable postDelete) {
-        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        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);
@@ -495,28 +488,12 @@ public abstract class XmppActivity extends ActionBarActivity {
         ExceptionHelper.init(getApplicationContext());
         EmojiInitializationService.execute(this);
         this.isCameraFeatureAvailable = getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
-        this.mTheme = findTheme();
-        setTheme(this.mTheme);
     }
 
     protected boolean isCameraFeatureAvailable() {
         return this.isCameraFeatureAvailable;
     }
 
-    public boolean isDarkTheme() {
-        return ThemeHelper.isDark(mTheme);
-    }
-
-    public int getThemeResource(int r_attr_name, int r_drawable_def) {
-        int[] attrs = {r_attr_name};
-        TypedArray ta = this.getTheme().obtainStyledAttributes(attrs);
-
-        int res = ta.getResourceId(0, r_drawable_def);
-        ta.recycle();
-
-        return res;
-    }
-
     protected boolean isOptimizingBattery() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             final PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
@@ -698,21 +675,10 @@ public abstract class XmppActivity extends ActionBarActivity {
         }
     }
 
-    @SuppressWarnings("deprecation")
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-    protected void setListItemBackgroundOnView(View view) {
-        int sdk = android.os.Build.VERSION.SDK_INT;
-        if (sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
-            view.setBackgroundDrawable(getResources().getDrawable(R.drawable.greybackground));
-        } else {
-            view.setBackground(getResources().getDrawable(R.drawable.greybackground));
-        }
-    }
-
-    protected void choosePgpSignId(Account account) {
-        xmppConnectionService.getPgpEngine().chooseKey(account, new UiCallback<Account>() {
+    protected void choosePgpSignId(final Account account) {
+        xmppConnectionService.getPgpEngine().chooseKey(account, new UiCallback<>() {
             @Override
-            public void success(Account account1) {
+            public void success(final Account a) {
             }
 
             @Override
@@ -733,8 +699,7 @@ public abstract class XmppActivity extends ActionBarActivity {
 
     protected void displayErrorDialog(final int errorCode) {
         runOnUiThread(() -> {
-            Builder builder = new Builder(XmppActivity.this);
-            builder.setIconAttribute(android.R.attr.alertDialogIcon);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(XmppActivity.this);
             builder.setTitle(getString(R.string.error));
             builder.setMessage(errorCode);
             builder.setNeutralButton(R.string.accept, null);
@@ -744,7 +709,7 @@ public abstract class XmppActivity extends ActionBarActivity {
     }
 
     protected void showAddToRosterDialog(final Contact contact) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setTitle(contact.getJid().toString());
         builder.setMessage(getString(R.string.not_in_roster));
         builder.setNegativeButton(getString(R.string.cancel), null);
@@ -753,7 +718,7 @@ public abstract class XmppActivity extends ActionBarActivity {
     }
 
     private void showAskForPresenceDialog(final Contact contact) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setTitle(contact.getJid().toString());
         builder.setMessage(R.string.request_presence_updates);
         builder.setNegativeButton(R.string.cancel, null);
@@ -787,8 +752,8 @@ public abstract class XmppActivity extends ActionBarActivity {
                            final @StringRes int hint,
                            boolean password,
                            boolean permitEmpty) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        DialogQuickeditBinding binding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.dialog_quickedit, null, false);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
+        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);
         }
@@ -829,7 +794,7 @@ public abstract class XmppActivity extends ActionBarActivity {
     }
 
     protected boolean hasStoragePermission(int requestCode) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+        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);
                 return false;
@@ -911,10 +876,6 @@ public abstract class XmppActivity extends ActionBarActivity {
         SettingsUtils.applyScreenshotPreventionSetting(this);
     }
 
-    protected int findTheme() {
-        return ThemeHelper.find(this);
-    }
-
     @Override
     public void onPause() {
         super.onPause();
@@ -936,14 +897,26 @@ public abstract class XmppActivity extends ActionBarActivity {
         if (uri == null || uri.isEmpty()) {
             return;
         }
-        Point size = new Point();
+        final Point size = new Point();
         getWindowManager().getDefaultDisplay().getSize(size);
-        final int width = (size.x < size.y ? size.x : size.y);
-        Bitmap bitmap = BarcodeProvider.create2dBarcodeBitmap(uri, width);
-        ImageView view = new ImageView(this);
-        view.setBackgroundColor(Color.WHITE);
+        final int width = Math.min(size.x, size.y);
+        final boolean nightMode = (this.getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        final int black;
+        final int white;
+        if (nightMode) {
+            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");
+        }
+        final var bitmap = BarcodeProvider.create2dBarcodeBitmap(uri, width, black, white);
+        final ImageView view = new ImageView(this);
+        view.setBackgroundColor(white);
         view.setImageBitmap(bitmap);
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
         builder.setView(view);
         builder.create().show();
     }

src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java 🔗

@@ -8,15 +8,16 @@ import android.widget.ArrayAdapter;
 import androidx.annotation.NonNull;
 import androidx.databinding.DataBindingUtil;
 
-import java.util.List;
+import com.google.android.material.color.MaterialColors;
 
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.AccountRowBinding;
+import eu.siacs.conversations.databinding.ItemAccountBinding;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
-import eu.siacs.conversations.ui.util.StyledAttributes;
+
+import java.util.List;
 
 public class AccountAdapter extends ArrayAdapter<Account> {
 
@@ -35,36 +36,33 @@ public class AccountAdapter extends ArrayAdapter<Account> {
         this.showStateButton = true;
     }
 
+    @NonNull
     @Override
     public View getView(int position, View view, @NonNull ViewGroup parent) {
         final Account account = getItem(position);
         final ViewHolder viewHolder;
         if (view == null) {
-            AccountRowBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.account_row, parent, false);
+            ItemAccountBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_account, parent, false);
             view = binding.getRoot();
             viewHolder = new ViewHolder(binding);
             view.setTag(viewHolder);
         } else {
             viewHolder = (ViewHolder) view.getTag();
         }
-        if (Config.DOMAIN_LOCK != null) {
-            viewHolder.binding.accountJid.setText(account.getJid().getLocal());
-        } else {
-            viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString());
-        }
+        viewHolder.binding.accountJid.setText(account.getJid().asBareJid().toEscapedString());
         AvatarWorkerTask.loadAvatar(account, viewHolder.binding.accountImage, R.dimen.avatar);
         viewHolder.binding.accountStatus.setText(getContext().getString(account.getStatus().getReadableId()));
         switch (account.getStatus()) {
             case ONLINE:
-                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorOnline));
+                viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorPrimary));
                 break;
             case DISABLED:
             case LOGGED_OUT:
             case CONNECTING:
-                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, android.R.attr.textColorSecondary));
+                viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorOnSurfaceVariant));
                 break;
             default:
-                viewHolder.binding.accountStatus.setTextColor(StyledAttributes.getColor(activity, R.attr.TextColorError));
+                viewHolder.binding.accountStatus.setTextColor(MaterialColors.getColor(viewHolder.binding.accountStatus, com.google.android.material.R.attr.colorError));
                 break;
         }
         final boolean isDisabled = (account.getStatus() == Account.State.DISABLED);
@@ -84,9 +82,9 @@ public class AccountAdapter extends ArrayAdapter<Account> {
     }
 
     private static class ViewHolder {
-        private final AccountRowBinding binding;
+        private final ItemAccountBinding binding;
 
-        private ViewHolder(AccountRowBinding binding) {
+        private ViewHolder(ItemAccountBinding binding) {
             this.binding = binding;
         }
     }

src/main/java/eu/siacs/conversations/ui/adapter/ChannelSearchResultAdapter.java 🔗

@@ -13,18 +13,18 @@ import androidx.recyclerview.widget.DiffUtil;
 import androidx.recyclerview.widget.ListAdapter;
 import androidx.recyclerview.widget.RecyclerView;
 
-import java.util.Locale;
-
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.SearchResultItemBinding;
+import eu.siacs.conversations.databinding.ItemChannelDiscoveryBinding;
 import eu.siacs.conversations.entities.Room;
 import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 import eu.siacs.conversations.xmpp.Jid;
 
+import java.util.Locale;
+
 public class ChannelSearchResultAdapter extends ListAdapter<Room, ChannelSearchResultAdapter.ViewHolder> implements View.OnCreateContextMenuListener {
 
-    private static final DiffUtil.ItemCallback<Room> DIFF = new DiffUtil.ItemCallback<Room>() {
+    private static final DiffUtil.ItemCallback<Room> DIFF = new DiffUtil.ItemCallback<>() {
         @Override
         public boolean areItemsTheSame(@NonNull Room a, @NonNull Room b) {
             return a.address != null && a.address.equals(b.address);
@@ -45,7 +45,7 @@ public class ChannelSearchResultAdapter extends ListAdapter<Room, ChannelSearchR
     @NonNull
     @Override
     public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
-        return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.search_result_item, viewGroup, false));
+        return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_channel_discovery, viewGroup, false));
     }
 
     @Override
@@ -99,9 +99,9 @@ public class ChannelSearchResultAdapter extends ListAdapter<Room, ChannelSearchR
 
     public static class ViewHolder extends RecyclerView.ViewHolder {
 
-        private final SearchResultItemBinding binding;
+        private final ItemChannelDiscoveryBinding binding;
 
-        private ViewHolder(SearchResultItemBinding binding) {
+        private ViewHolder(final ItemChannelDiscoveryBinding binding) {
             super(binding.getRoot());
             this.binding = binding;
         }

src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java 🔗

@@ -6,30 +6,30 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.databinding.DataBindingUtil;
 import androidx.recyclerview.widget.RecyclerView;
 
+import com.google.android.material.color.MaterialColors;
 import com.google.common.base.Optional;
-import com.google.common.base.Strings;
-
-import java.util.List;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ConversationListRowBinding;
+import eu.siacs.conversations.databinding.ItemConversationBinding;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Conversational;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.ui.ConversationFragment;
 import eu.siacs.conversations.ui.XmppActivity;
+import eu.siacs.conversations.ui.util.Attachment;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.IrregularUnicodeDetector;
-import eu.siacs.conversations.utils.MimeUtils;
 import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.xmpp.Jid;
 import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession;
 
+import java.util.List;
+
 public class ConversationAdapter
         extends RecyclerView.Adapter<ConversationAdapter.ConversationViewHolder> {
 
@@ -48,7 +48,7 @@ public class ConversationAdapter
         return new ConversationViewHolder(
                 DataBindingUtil.inflate(
                         LayoutInflater.from(parent.getContext()),
-                        R.layout.conversation_list_row,
+                        R.layout.item_conversation,
                         parent,
                         false));
     }
@@ -68,14 +68,13 @@ public class ConversationAdapter
         }
 
         if (conversation == ConversationFragment.getConversation(activity)) {
-            viewHolder.binding.frame.setBackgroundColor(
-                    StyledAttributes.getColor(activity, R.attr.color_background_tertiary));
+            viewHolder.binding.frame.setBackgroundResource(R.drawable.background_selected_item_conversation);
+            //viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurfaceDim));
         } else {
-            viewHolder.binding.frame.setBackgroundColor(
-                    StyledAttributes.getColor(activity, R.attr.color_background_primary));
+            viewHolder.binding.frame.setBackgroundColor(MaterialColors.getColor(viewHolder.binding.frame, com.google.android.material.R.attr.colorSurface));
         }
 
-        Message message = conversation.getLatestMessage();
+        final Message message = conversation.getLatestMessage();
         final int unreadCount = conversation.unreadCount();
         final boolean isRead = conversation.isRead();
         final Conversation.Draft draft = isRead ? conversation.getDraft() : null;
@@ -106,68 +105,9 @@ public class ConversationAdapter
                     && (message.isFileOrImage()
                             || message.treatAsDownloadable()
                             || message.isGeoUri())) {
-                final int imageResource;
-                if (message.isGeoUri()) {
-                    imageResource =
-                            activity.getThemeResource(
-                                    R.attr.ic_attach_location, R.drawable.ic_attach_location);
-                    showPreviewText = false;
-                } else {
-                    // TODO move this into static MediaPreview method and use same icons as in
-                    // MediaAdapter
-                    final String mime = message.getMimeType();
-                    if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) {
-                        final Message.FileParams fileParams = message.getFileParams();
-                        if (fileParams.width > 0 && fileParams.height > 0) {
-                            imageResource =
-                                    activity.getThemeResource(
-                                            R.attr.ic_attach_videocam,
-                                            R.drawable.ic_attach_videocam);
-                            showPreviewText = false;
-                        } else if (fileParams.runtime > 0) {
-                            imageResource =
-                                    activity.getThemeResource(
-                                            R.attr.ic_attach_record, R.drawable.ic_attach_record);
-                            showPreviewText = false;
-                        } else {
-                            imageResource =
-                                    activity.getThemeResource(
-                                            R.attr.ic_attach_document,
-                                            R.drawable.ic_attach_document);
-                            showPreviewText = true;
-                        }
-                    } else {
-                        switch (Strings.nullToEmpty(mime).split("/")[0]) {
-                            case "image":
-                                imageResource =
-                                        activity.getThemeResource(
-                                                R.attr.ic_attach_photo, R.drawable.ic_attach_photo);
-                                showPreviewText = false;
-                                break;
-                            case "video":
-                                imageResource =
-                                        activity.getThemeResource(
-                                                R.attr.ic_attach_videocam,
-                                                R.drawable.ic_attach_videocam);
-                                showPreviewText = false;
-                                break;
-                            case "audio":
-                                imageResource =
-                                        activity.getThemeResource(
-                                                R.attr.ic_attach_record,
-                                                R.drawable.ic_attach_record);
-                                showPreviewText = false;
-                                break;
-                            default:
-                                imageResource =
-                                        activity.getThemeResource(
-                                                R.attr.ic_attach_document,
-                                                R.drawable.ic_attach_document);
-                                showPreviewText = true;
-                                break;
-                        }
-                    }
-                }
+                final var attachment = Attachment.of(message);
+                final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
+                showPreviewText = false;
                 viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource);
                 viewHolder.binding.conversationLastmsgImg.setVisibility(View.VISIBLE);
             } else {
@@ -231,36 +171,21 @@ public class ConversationAdapter
 
         if (ongoingCall.isPresent()) {
             viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
-            final int ic_ongoing_call =
-                    activity.getThemeResource(
-                            R.attr.ic_ongoing_call_hint, R.drawable.ic_phone_in_talk_black_18dp);
-            viewHolder.binding.notificationStatus.setImageResource(ic_ongoing_call);
+            viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_phone_in_talk_24dp);
         } else {
             final long muted_till =
                     conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0);
             if (muted_till == Long.MAX_VALUE) {
                 viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
-                int ic_notifications_off =
-                        activity.getThemeResource(
-                                R.attr.icon_notifications_off,
-                                R.drawable.ic_notifications_off_black_24dp);
-                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_off);
+                viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_off_24dp);
             } else if (muted_till >= System.currentTimeMillis()) {
                 viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
-                int ic_notifications_paused =
-                        activity.getThemeResource(
-                                R.attr.icon_notifications_paused,
-                                R.drawable.ic_notifications_paused_black_24dp);
-                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_paused);
+                viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_paused_24dp);
             } else if (conversation.alwaysNotify()) {
                 viewHolder.binding.notificationStatus.setVisibility(View.GONE);
             } else {
                 viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE);
-                int ic_notifications_none =
-                        activity.getThemeResource(
-                                R.attr.icon_notifications_none,
-                                R.drawable.ic_notifications_none_black_24dp);
-                viewHolder.binding.notificationStatus.setImageResource(ic_notifications_none);
+                viewHolder.binding.notificationStatus.setImageResource(R.drawable.ic_notifications_none_24dp);
             }
         }
 
@@ -307,9 +232,9 @@ public class ConversationAdapter
     }
 
     static class ConversationViewHolder extends RecyclerView.ViewHolder {
-        private final ConversationListRowBinding binding;
+        private final ItemConversationBinding binding;
 
-        private ConversationViewHolder(ConversationListRowBinding binding) {
+        private ConversationViewHolder(final ItemConversationBinding binding) {
             super(binding.getRoot());
             this.binding = binding;
         }

src/main/java/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java 🔗

@@ -6,32 +6,35 @@ import android.widget.Filter;
 
 import androidx.annotation.NonNull;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Ordering;
+
+import eu.siacs.conversations.Config;
+
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 import java.util.regex.Pattern;
 
-import eu.siacs.conversations.Config;
-
 public class KnownHostsAdapter extends ArrayAdapter<String> {
 
     private static final Pattern E164_PATTERN = Pattern.compile("^\\+[1-9]\\d{1,14}$");
 
-    private ArrayList<String> domains;
+    private List<String> domains;
     private final Filter domainFilter = new Filter() {
 
         @Override
-        protected FilterResults performFiltering(CharSequence constraint) {
-            final ArrayList<String> suggestions = new ArrayList<>();
+        protected FilterResults performFiltering(final CharSequence constraint) {
+            final ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
             final String[] split = constraint == null ? new String[0] : constraint.toString().split("@");
             if (split.length == 1) {
                 final String local = split[0].toLowerCase(Locale.ENGLISH);
                 if (Config.QUICKSY_DOMAIN != null && E164_PATTERN.matcher(local).matches()) {
-                    suggestions.add(local + '@' + Config.QUICKSY_DOMAIN.toEscapedString());
+                    builder.add(local + '@' + Config.QUICKSY_DOMAIN.toEscapedString());
                 } else {
                     for (String domain : domains) {
-                        suggestions.add(local + '@' + domain);
+                        builder.add(local + '@' + domain);
                     }
                 }
             } else if (split.length == 2) {
@@ -40,45 +43,49 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
                 if (domains.contains(domainPart)) {
                     return new FilterResults();
                 }
-                for (String domain : domains) {
+                for (final String domain : domains) {
                     if (domain.contains(domainPart)) {
-                        suggestions.add(localPart + "@" + domain);
+                        builder.add(localPart + "@" + domain);
                     }
                 }
             } else {
                 return new FilterResults();
             }
-            FilterResults filterResults = new FilterResults();
+            final var suggestions = builder.build();
+            final FilterResults filterResults = new FilterResults();
             filterResults.values = suggestions;
             filterResults.count = suggestions.size();
             return filterResults;
         }
 
         @Override
-        protected void publishResults(CharSequence constraint, FilterResults results) {
-            ArrayList filteredList = (ArrayList) results.values;
-            if (results.count > 0) {
-                clear();
-                addAll(filteredList);
-                notifyDataSetChanged();
+        protected void publishResults(final CharSequence constraint, final FilterResults results) {
+            final ImmutableList.Builder<String> suggestions = new ImmutableList.Builder<>();
+            if (results.values instanceof Collection<?> collection) {
+                for(final Object item : collection) {
+                    if (item instanceof String string) {
+                        suggestions.add(string);
+                    }
+                }
             }
+            clear();
+            addAll(suggestions.build());
+            notifyDataSetChanged();
         }
     };
 
-    public KnownHostsAdapter(Context context, int viewResourceId, Collection<String> mKnownHosts) {
+    public KnownHostsAdapter(final Context context, final int viewResourceId, final Collection<String> knownHosts) {
         super(context, viewResourceId, new ArrayList<>());
-        domains = new ArrayList<>(mKnownHosts);
-        Collections.sort(domains);
+        domains =  Ordering.natural().sortedCopy(knownHosts);
     }
 
-    public KnownHostsAdapter(Context context, int viewResourceId) {
+    public KnownHostsAdapter(final Context context, final int viewResourceId) {
         super(context, viewResourceId, new ArrayList<>());
-        domains = new ArrayList<>();
+        domains = ImmutableList.of();
     }
 
-    public void refresh(Collection<String> knownHosts) {
-        domains = new ArrayList<>(knownHosts);
-        Collections.sort(domains);
+    public void refresh(final Collection<String> knownHosts) {
+        this.domains = Ordering.natural().sortedCopy(knownHosts);
         notifyDataSetChanged();
     }
 

src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java 🔗

@@ -2,6 +2,7 @@ package eu.siacs.conversations.ui.adapter;
 
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -9,30 +10,30 @@ import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.databinding.DataBindingUtil;
 
 import com.wefika.flowlayout.FlowLayout;
 
-import java.util.List;
-
+import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ContactBinding;
+import eu.siacs.conversations.databinding.ItemContactBinding;
 import eu.siacs.conversations.entities.ListItem;
 import eu.siacs.conversations.ui.SettingsActivity;
 import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.utils.IrregularUnicodeDetector;
 import eu.siacs.conversations.xmpp.Jid;
 
+import java.util.List;
+
 public class ListItemAdapter extends ArrayAdapter<ListItem> {
 
 	protected XmppActivity activity;
 	private boolean showDynamicTags = false;
 	private OnTagClickedListener mOnTagClickedListener = null;
 	private final View.OnClickListener onTagTvClick = view -> {
-		if (view instanceof TextView && mOnTagClickedListener != null) {
-			TextView tv = (TextView) view;
+		if (view instanceof TextView tv && mOnTagClickedListener != null) {
 			final String tag = tv.getText().toString();
 			mOnTagClickedListener.onTagClicked(tag);
 		}
@@ -49,22 +50,25 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
 		this.showDynamicTags = preferences.getBoolean(SettingsActivity.SHOW_DYNAMIC_TAGS, false);
 	}
 
+	@NonNull
 	@Override
-	public View getView(int position, View view, ViewGroup parent) {
+	public View getView(int position, View view, @NonNull ViewGroup parent) {
 		LayoutInflater inflater = activity.getLayoutInflater();
 		ListItem item = getItem(position);
 		ViewHolder viewHolder;
 		if (view == null) {
-			ContactBinding binding = DataBindingUtil.inflate(inflater,R.layout.contact,parent,false);
+			final ItemContactBinding binding = DataBindingUtil.inflate(inflater,R.layout.item_contact,parent,false);
 			viewHolder = ViewHolder.get(binding);
 			view = binding.getRoot();
 		} else {
 			viewHolder = (ViewHolder) view.getTag();
 		}
-		view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));
-
-		List<ListItem.Tag> tags = item.getTags(activity);
-		if (tags.size() == 0 || !this.showDynamicTags) {
+		if (view.isActivated()) {
+			Log.d(Config.LOGTAG,"item "+item.getDisplayName()+" is activated");
+		}
+		//view.setBackground(StyledAttributes.getDrawable(view.getContext(),R.attr.list_item_background));
+		final List<ListItem.Tag> tags = item.getTags(activity);
+		if (tags.isEmpty() || !this.showDynamicTags) {
 			viewHolder.tags.setVisibility(View.GONE);
 		} else {
 			viewHolder.tags.setVisibility(View.VISIBLE);
@@ -108,7 +112,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
 
 		}
 
-		public static ViewHolder get(ContactBinding binding) {
+		public static ViewHolder get(final ItemContactBinding binding) {
 			ViewHolder viewHolder = new ViewHolder();
 			viewHolder.name = binding.contactDisplayName;
 			viewHolder.jid = binding.contactJid;

src/main/java/eu/siacs/conversations/ui/adapter/MediaAdapter.java 🔗

@@ -1,47 +1,50 @@
 package eu.siacs.conversations.ui.adapter;
 
-import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
-import androidx.annotation.AttrRes;
 import androidx.annotation.DimenRes;
+import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
+import androidx.core.widget.ImageViewCompat;
 import androidx.databinding.DataBindingUtil;
 import androidx.recyclerview.widget.RecyclerView;
 
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.RejectedExecutionException;
+import com.google.android.material.color.MaterialColors;
+import com.google.common.base.Strings;
 
-import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.MediaBinding;
+import eu.siacs.conversations.databinding.ItemMediaBinding;
 import eu.siacs.conversations.services.ExportBackupService;
 import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.Attachment;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.ui.util.ViewUtil;
 
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
 public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHolder> {
 
-    public static final List<String> DOCUMENT_MIMES = Arrays.asList(
-            "application/pdf",
-            "application/vnd.oasis.opendocument.text",
-            "application/msword",
-            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
-            "text/x-tex",
-            "text/plain"
-    );
+    public static final List<String> DOCUMENT_MIMES =
+            Arrays.asList(
+                    "application/pdf",
+                    "application/vnd.oasis.opendocument.text",
+                    "application/msword",
+                    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+                    "text/x-tex",
+                    "text/plain");
+    public static final List<String> CODE_MIMES = Arrays.asList("text/html", "text/xml");
 
     private final ArrayList<Attachment> attachments = new ArrayList<>();
 
@@ -55,58 +58,77 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
     }
 
     @SuppressWarnings("rawtypes")
-    public static void setMediaSize(RecyclerView recyclerView, int mediaSize) {
+    public static void setMediaSize(final RecyclerView recyclerView, int mediaSize) {
         final RecyclerView.Adapter adapter = recyclerView.getAdapter();
-        if (adapter instanceof MediaAdapter) {
-            ((MediaAdapter) adapter).setMediaSize(mediaSize);
+        if (adapter instanceof MediaAdapter mediaAdapter) {
+            mediaAdapter.setMediaSize(mediaSize);
         }
     }
 
-    private static @AttrRes
-    int getImageAttr(Attachment attachment) {
-        final @AttrRes int attr;
+    public static @DrawableRes int getImageDrawable(final Attachment attachment) {
         if (attachment.getType() == Attachment.Type.LOCATION) {
-            attr = R.attr.media_preview_location;
+            return R.drawable.ic_location_pin_48dp;
         } else if (attachment.getType() == Attachment.Type.RECORDING) {
-            attr = R.attr.media_preview_recording;
+            return R.drawable.ic_mic_48dp;
         } else {
-            final String mime = attachment.getMime();
-            Log.d(Config.LOGTAG, "mime=" + mime);
-            if (mime == null) {
-                attr = R.attr.media_preview_unknown;
-            } else if (mime.equals("audio/x-m4b")) {
-                attr = R.attr.media_preview_audiobook;
-            } else if (mime.startsWith("audio/")) {
-                attr = R.attr.media_preview_audio;
-            } else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) {
-                attr = R.attr.media_preview_calendar;
-            } else if (mime.equals("text/x-vcard")) {
-                attr = R.attr.media_preview_contact;
-            } else if (mime.equals("application/vnd.android.package-archive")) {
-                attr = R.attr.media_preview_app;
-            } else if (mime.equals("application/zip") || mime.equals("application/rar")) {
-                attr = R.attr.media_preview_archive;
-            } else if (mime.equals("application/epub+zip") || mime.equals("application/vnd.amazon.mobi8-ebook")) {
-                attr = R.attr.media_preview_ebook;
-            } else if (mime.equals(ExportBackupService.MIME_TYPE)) {
-                attr = R.attr.media_preview_backup;
-            } else if (DOCUMENT_MIMES.contains(mime)) {
-                attr = R.attr.media_preview_document;
-            } else if (mime.equals("application/gpx+xml")) {
-                attr = R.attr.media_preview_tour;
-            } else if (mime.startsWith("image/")) {
-                attr = R.attr.media_preview_image;
-            } else {
-                attr = R.attr.media_preview_unknown;
-            }
+            return getImageDrawable(attachment.getMime());
+        }
+    }
+
+    private static @DrawableRes int getImageDrawable(final String mime) {
+
+        // TODO ideas for more mime types: XML, HTML documents, GPG/PGP files, eml files,
+        // spreadsheets (table symbol)
+
+        // add bz2 and tar.gz to archive detection
+
+        if (Strings.isNullOrEmpty(mime)) {
+            return R.drawable.ic_help_center_48dp;
+        } else if (mime.equals("audio/x-m4b")) {
+            return R.drawable.ic_play_lesson_48dp;
+        } else if (mime.startsWith("audio/")) {
+            return R.drawable.ic_headphones_48dp;
+        } else if (mime.equals("text/calendar") || (mime.equals("text/x-vcalendar"))) {
+            return R.drawable.ic_event_48dp;
+        } else if (mime.equals("text/x-vcard")) {
+            return R.drawable.ic_person_48dp;
+        } else if (mime.equals("application/vnd.android.package-archive")) {
+            return R.drawable.ic_adb_48dp;
+        } else if (mime.equals("application/zip") || mime.equals("application/rar")) {
+            return R.drawable.ic_archive_48dp;
+        } else if (mime.equals("application/epub+zip")
+                || mime.equals("application/vnd.amazon.mobi8-ebook")) {
+            return R.drawable.ic_book_48dp;
+        } else if (mime.equals(ExportBackupService.MIME_TYPE)) {
+            return R.drawable.ic_backup_48dp;
+        } else if (DOCUMENT_MIMES.contains(mime)) {
+            return R.drawable.ic_description_48dp;
+        } else if (mime.equals("application/gpx+xml")) {
+            return R.drawable.ic_tour_48dp;
+        } else if (mime.startsWith("image/")) {
+            return R.drawable.ic_image_48dp;
+        } else if (mime.startsWith("video/")) {
+            return R.drawable.ic_movie_48dp;
+        } else if (CODE_MIMES.contains(mime)) {
+            return R.drawable.ic_code_48dp;
+        } else if (mime.equals("message/rfc822")) {
+            return R.drawable.ic_email_48dp;
+        } else {
+            return R.drawable.ic_help_center_48dp;
         }
-        return attr;
     }
 
-    static void renderPreview(Context context, Attachment attachment, ImageView imageView) {
-        imageView.setBackgroundColor(StyledAttributes.getColor(context, R.attr.color_background_tertiary));
-        imageView.setImageAlpha(Math.round(StyledAttributes.getFloat(context, R.attr.icon_alpha) * 255));
-        imageView.setImageDrawable(StyledAttributes.getDrawable(context, getImageAttr(attachment)));
+    static void renderPreview(final Attachment attachment, final ImageView imageView) {
+        ImageViewCompat.setImageTintList(
+                imageView,
+                ColorStateList.valueOf(
+                        MaterialColors.getColor(
+                                imageView, com.google.android.material.R.attr.colorOnSurface)));
+        imageView.setImageResource(getImageDrawable(attachment));
+        imageView.setBackgroundColor(
+                MaterialColors.getColor(
+                        imageView,
+                        com.google.android.material.R.attr.colorSurfaceContainerHighest));
     }
 
     private static boolean cancelPotentialWork(Attachment attachment, ImageView imageView) {
@@ -126,8 +148,7 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
     private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
         if (imageView != null) {
             final Drawable drawable = imageView.getDrawable();
-            if (drawable instanceof AsyncDrawable) {
-                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+            if (drawable instanceof AsyncDrawable asyncDrawable) {
                 return asyncDrawable.getBitmapWorkerTask();
             }
         }
@@ -137,8 +158,9 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
     @NonNull
     @Override
     public MediaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
-        MediaBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media, parent, false);
+        final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+        ItemMediaBinding binding =
+                DataBindingUtil.inflate(layoutInflater, R.layout.item_media, parent, false);
         return new MediaViewHolder(binding);
     }
 
@@ -146,16 +168,15 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
     public void onBindViewHolder(@NonNull MediaViewHolder holder, int position) {
         final Attachment attachment = attachments.get(position);
         if (attachment.renderThumbnail()) {
-            holder.binding.media.setImageAlpha(255);
             loadPreview(attachment, holder.binding.media);
         } else {
             cancelPotentialWork(attachment, holder.binding.media);
-            renderPreview(activity, attachment, holder.binding.media);
+            renderPreview(attachment, holder.binding.media);
         }
         holder.binding.getRoot().setOnClickListener(v -> ViewUtil.view(activity, attachment));
     }
 
-    public void setAttachments(List<Attachment> attachments) {
+    public void setAttachments(final List<Attachment> attachments) {
         this.attachments.clear();
         this.attachments.addAll(attachments);
         notifyDataSetChanged();
@@ -167,16 +188,21 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
 
     private void loadPreview(Attachment attachment, ImageView imageView) {
         if (cancelPotentialWork(attachment, imageView)) {
-            final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment, mediaSize, true);
+            final Bitmap bm =
+                    activity.xmppConnectionService
+                            .getFileBackend()
+                            .getPreviewForUri(attachment, mediaSize, true);
             if (bm != null) {
                 cancelPotentialWork(attachment, imageView);
                 imageView.setImageBitmap(bm);
-                imageView.setBackgroundColor(0x00000000);
+                imageView.setBackgroundColor(Color.TRANSPARENT);
             } else {
+                // TODO consider if this is still a good, general purpose loading color
                 imageView.setBackgroundColor(0xff333333);
                 imageView.setImageDrawable(null);
                 final BitmapWorkerTask task = new BitmapWorkerTask(mediaSize, imageView);
-                final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
+                final AsyncDrawable asyncDrawable =
+                        new AsyncDrawable(activity.getResources(), null, task);
                 imageView.setImageDrawable(asyncDrawable);
                 try {
                     task.execute(attachment);
@@ -204,11 +230,11 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
         }
     }
 
-    class MediaViewHolder extends RecyclerView.ViewHolder {
+    static class MediaViewHolder extends RecyclerView.ViewHolder {
 
-        private final MediaBinding binding;
+        private final ItemMediaBinding binding;
 
-        MediaViewHolder(MediaBinding binding) {
+        MediaViewHolder(ItemMediaBinding binding) {
             super(binding.getRoot());
             this.binding = binding;
         }
@@ -225,13 +251,15 @@ public class MediaAdapter extends RecyclerView.Adapter<MediaAdapter.MediaViewHol
         }
 
         @Override
-        protected Bitmap doInBackground(Attachment... params) {
+        protected Bitmap doInBackground(final Attachment... params) {
             this.attachment = params[0];
             final XmppActivity activity = XmppActivity.find(imageViewReference);
             if (activity == null) {
                 return null;
             }
-            return activity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, mediaSize, false);
+            return activity.xmppConnectionService
+                    .getFileBackend()
+                    .getPreviewForUri(this.attachment, mediaSize, false);
         }
 
         @Override

src/main/java/eu/siacs/conversations/ui/adapter/MediaPreviewAdapter.java 🔗

@@ -15,22 +15,25 @@ import android.widget.ImageView;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
+import androidx.core.widget.ImageViewCompat;
 import androidx.databinding.DataBindingUtil;
 import androidx.recyclerview.widget.RecyclerView;
 
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.RejectedExecutionException;
-
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.MediaPreviewBinding;
+import eu.siacs.conversations.databinding.ItemMediaPreviewBinding;
 import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.ui.ConversationFragment;
 import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.Attachment;
 
-public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapter.MediaPreviewViewHolder> {
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+public class MediaPreviewAdapter
+        extends RecyclerView.Adapter<MediaPreviewAdapter.MediaPreviewViewHolder> {
 
     private final ArrayList<Attachment> mediaPreviews = new ArrayList<>();
 
@@ -43,8 +46,9 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
     @NonNull
     @Override
     public MediaPreviewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
-        MediaPreviewBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.media_preview, parent, false);
+        final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+        ItemMediaPreviewBinding binding =
+                DataBindingUtil.inflate(layoutInflater, R.layout.item_media_preview, parent, false);
         return new MediaPreviewViewHolder(binding);
     }
 
@@ -53,18 +57,19 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
         final Context context = conversationFragment.getActivity();
         final Attachment attachment = mediaPreviews.get(position);
         if (attachment.renderThumbnail()) {
-            holder.binding.mediaPreview.setImageAlpha(255);
+            ImageViewCompat.setImageTintList(holder.binding.mediaPreview, null);
             loadPreview(attachment, holder.binding.mediaPreview);
         } else {
             cancelPotentialWork(attachment, holder.binding.mediaPreview);
-            MediaAdapter.renderPreview(context, attachment, holder.binding.mediaPreview);
+            MediaAdapter.renderPreview(attachment, holder.binding.mediaPreview);
         }
-        holder.binding.deleteButton.setOnClickListener(v -> {
-            final int pos = mediaPreviews.indexOf(attachment);
-            mediaPreviews.remove(pos);
-            notifyItemRemoved(pos);
-            conversationFragment.toggleInputMethod();
-        });
+        holder.binding.deleteButton.setOnClickListener(
+                v -> {
+                    final int pos = mediaPreviews.indexOf(attachment);
+                    mediaPreviews.remove(pos);
+                    notifyItemRemoved(pos);
+                    conversationFragment.toggleInputMethod();
+                });
         holder.binding.mediaPreview.setOnClickListener(v -> view(context, attachment));
     }
 
@@ -76,9 +81,14 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
         try {
             context.startActivity(view);
         } catch (final ActivityNotFoundException e) {
-            Toast.makeText(context, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show();
+            Toast.makeText(context, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT)
+                    .show();
         } catch (final SecurityException e) {
-            Toast.makeText(context, R.string.sharing_application_not_grant_permission, Toast.LENGTH_SHORT).show();
+            Toast.makeText(
+                            context,
+                            R.string.sharing_application_not_grant_permission,
+                            Toast.LENGTH_SHORT)
+                    .show();
         }
     }
 
@@ -90,16 +100,27 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
     private void loadPreview(Attachment attachment, ImageView imageView) {
         if (cancelPotentialWork(attachment, imageView)) {
             XmppActivity activity = (XmppActivity) conversationFragment.getActivity();
-            final Bitmap bm = activity.xmppConnectionService.getFileBackend().getPreviewForUri(attachment,Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)),true);
+            final Bitmap bm =
+                    activity.xmppConnectionService
+                            .getFileBackend()
+                            .getPreviewForUri(
+                                    attachment,
+                                    Math.round(
+                                            activity.getResources()
+                                                    .getDimension(R.dimen.media_preview_size)),
+                                    true);
             if (bm != null) {
                 cancelPotentialWork(attachment, imageView);
                 imageView.setImageBitmap(bm);
                 imageView.setBackgroundColor(0x00000000);
             } else {
-                imageView.setBackgroundColor(0xff333333);
+                imageView.setBackgroundColor(
+                        ContextCompat.getColor(imageView.getContext(), R.color.gray_800));
                 imageView.setImageDrawable(null);
                 final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
-                final AsyncDrawable asyncDrawable = new AsyncDrawable(conversationFragment.getActivity().getResources(), null, task);
+                final AsyncDrawable asyncDrawable =
+                        new AsyncDrawable(
+                                conversationFragment.getActivity().getResources(), null, task);
                 imageView.setImageDrawable(asyncDrawable);
                 try {
                     task.execute(attachment);
@@ -126,8 +147,7 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
     private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
         if (imageView != null) {
             final Drawable drawable = imageView.getDrawable();
-            if (drawable instanceof AsyncDrawable) {
-                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+            if (drawable instanceof AsyncDrawable asyncDrawable) {
                 return asyncDrawable.getBitmapWorkerTask();
             }
         }
@@ -140,7 +160,7 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
     }
 
     public boolean hasAttachments() {
-        return mediaPreviews.size() > 0;
+        return !mediaPreviews.isEmpty();
     }
 
     public ArrayList<Attachment> getAttachments() {
@@ -153,9 +173,9 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
 
     static class MediaPreviewViewHolder extends RecyclerView.ViewHolder {
 
-        private final MediaPreviewBinding binding;
+        private final ItemMediaPreviewBinding binding;
 
-        MediaPreviewViewHolder(MediaPreviewBinding binding) {
+        MediaPreviewViewHolder(ItemMediaPreviewBinding binding) {
             super(binding.getRoot());
             this.binding = binding;
         }
@@ -189,7 +209,14 @@ public class MediaPreviewAdapter extends RecyclerView.Adapter<MediaPreviewAdapte
             if (activity == null) {
                 return null;
             }
-            return activity.xmppConnectionService.getFileBackend().getPreviewForUri(this.attachment, Math.round(activity.getResources().getDimension(R.dimen.media_preview_size)), false);
+            return activity.xmppConnectionService
+                    .getFileBackend()
+                    .getPreviewForUri(
+                            this.attachment,
+                            Math.round(
+                                    activity.getResources()
+                                            .getDimension(R.dimen.media_preview_size)),
+                            false);
         }
 
         @Override

src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java 🔗

@@ -5,6 +5,7 @@ import android.app.Activity;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
 import android.graphics.Typeface;
 import android.os.Build;
 import android.preference.PreferenceManager;
@@ -20,16 +21,22 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.ArrayAdapter;
-import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import androidx.annotation.AttrRes;
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
+import androidx.core.widget.ImageViewCompat;
 
+import com.google.android.material.button.MaterialButton;
+import com.google.android.material.color.MaterialColors;
 import com.google.common.base.Strings;
 
 import java.net.URI;
@@ -58,6 +65,7 @@ import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.service.AudioPlayer;
 import eu.siacs.conversations.ui.text.DividerSpan;
 import eu.siacs.conversations.ui.text.QuoteSpan;
+import eu.siacs.conversations.ui.util.Attachment;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 import eu.siacs.conversations.ui.util.MyLinkify;
 import eu.siacs.conversations.ui.util.QuoteHelper;
@@ -160,15 +168,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         return this.getItemViewType(getItem(position));
     }
 
-    private int getMessageTextColor(boolean onDark, boolean primary) {
-        if (onDark) {
-            return ContextCompat.getColor(activity, primary ? R.color.white : R.color.white70);
-        } else {
-            return ContextCompat.getColor(activity, primary ? R.color.black87 : R.color.black54);
-        }
-    }
-
-    private void displayStatus(ViewHolder viewHolder, Message message, int type, boolean darkBackground) {
+    private void displayStatus(ViewHolder viewHolder, Message message, int type, final BubbleColor bubbleColor) {
         String filesize = null;
         String info = null;
         boolean error = false;
@@ -179,8 +179,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         if (viewHolder.edit_indicator != null) {
             if (message.edited()) {
                 viewHolder.edit_indicator.setVisibility(View.VISIBLE);
-                viewHolder.edit_indicator.setImageResource(darkBackground ? R.drawable.ic_mode_edit_white_18dp : R.drawable.ic_mode_edit_black_18dp);
-                viewHolder.edit_indicator.setAlpha(darkBackground ? 0.7f : 0.57f);
+                setImageTint(viewHolder.edit_indicator, bubbleColor);
             } else {
                 viewHolder.edit_indicator.setVisibility(View.GONE);
             }
@@ -211,8 +210,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                 break;
             case Message.STATUS_SEND_RECEIVED:
             case Message.STATUS_SEND_DISPLAYED:
-                viewHolder.indicatorReceived.setImageResource(darkBackground ? R.drawable.ic_done_white_18dp : R.drawable.ic_done_black_18dp);
-                viewHolder.indicatorReceived.setAlpha(darkBackground ? 0.7f : 0.57f);
+                setImageTint(viewHolder.indicatorReceived, bubbleColor);
                 viewHolder.indicatorReceived.setVisibility(View.VISIBLE);
                 break;
             case Message.STATUS_SEND_FAILED:
@@ -245,18 +243,9 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                 break;
         }
         if (error && type == SENT) {
-            if (darkBackground) {
-                viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption_Warning_OnDark);
-            } else {
-                viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption_Warning);
-            }
+            viewHolder.time.setTextColor(MaterialColors.getColor(viewHolder.time, com.google.android.material.R.attr.colorError));
         } else {
-            if (darkBackground) {
-                viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption_OnDark);
-            } else {
-                viewHolder.time.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Caption);
-            }
-            viewHolder.time.setTextColor(this.getMessageTextColor(darkBackground, false));
+            setTextColor(viewHolder.time,bubbleColor);
         }
         if (message.getEncryption() == Message.ENCRYPTION_NONE) {
             viewHolder.indicator.setVisibility(View.GONE);
@@ -271,15 +260,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                 }
             }
             if (verified) {
-                viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_verified_user_white_18dp : R.drawable.ic_verified_user_black_18dp);
-            } else {
-                viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_lock_white_18dp : R.drawable.ic_lock_black_18dp);
-            }
-            if (darkBackground) {
-                viewHolder.indicator.setAlpha(0.7f);
+                viewHolder.indicator.setImageResource(R.drawable.ic_verified_user_24dp);
             } else {
-                viewHolder.indicator.setAlpha(0.57f);
+                viewHolder.indicator.setImageResource(R.drawable.ic_lock_24dp);
             }
+            setImageTint(viewHolder.indicator, bubbleColor);
             viewHolder.indicator.setVisibility(View.VISIBLE);
         }
 
@@ -313,37 +298,29 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         }
     }
 
-    private void displayInfoMessage(ViewHolder viewHolder, CharSequence text, boolean darkBackground) {
+    private void displayInfoMessage(ViewHolder viewHolder, CharSequence text, final BubbleColor bubbleColor) {
         viewHolder.download_button.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.messageBody.setVisibility(View.VISIBLE);
         viewHolder.messageBody.setText(text);
-        if (darkBackground) {
-            viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Secondary_OnDark);
-        } else {
-            viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Secondary);
-        }
+        viewHolder.messageBody.setTextColor(bubbleToOnSurfaceVariant(viewHolder.messageBody,bubbleColor));
         viewHolder.messageBody.setTextIsSelectable(false);
     }
 
-    private void displayEmojiMessage(final ViewHolder viewHolder, final String body, final boolean darkBackground) {
+    private void displayEmojiMessage(final ViewHolder viewHolder, final String body, final BubbleColor bubbleColor) {
         viewHolder.download_button.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.messageBody.setVisibility(View.VISIBLE);
-        if (darkBackground) {
-            viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Emoji_OnDark);
-        } else {
-            viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_Emoji);
-        }
-        Spannable span = new SpannableString(body);
+        setTextColor(viewHolder.messageBody, bubbleColor);
+        final Spannable span = new SpannableString(body);
         float size = Emoticons.isEmoji(body) ? 3.0f : 2.0f;
         span.setSpan(new RelativeSizeSpan(size), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
         viewHolder.messageBody.setText(span);
     }
 
-    private void applyQuoteSpan(SpannableStringBuilder body, int start, int end, boolean darkBackground) {
+    private void applyQuoteSpan(final TextView textView, SpannableStringBuilder body, int start, int end, final BubbleColor bubbleColor) {
         if (start > 1 && !"\n\n".equals(body.subSequence(start - 2, start).toString())) {
             body.insert(start++, "\n");
             body.setSpan(new DividerSpan(false), start - 2, start, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -353,17 +330,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             body.insert(end, "\n");
             body.setSpan(new DividerSpan(false), end, end + 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
         }
-        int color = darkBackground ? this.getMessageTextColor(darkBackground, false)
-                : ContextCompat.getColor(activity, R.color.green700_desaturated);
-        DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
-        body.setSpan(new QuoteSpan(color, metrics), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+        body.setSpan(new QuoteSpan(bubbleToOnSurfaceVariant(textView, bubbleColor), metrics), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
     /**
      * Applies QuoteSpan to group of lines which starts with > or » characters.
      * Appends likebreaks and applies DividerSpan to them to show a padding between quote and text.
      */
-    private boolean handleTextQuotes(SpannableStringBuilder body, boolean darkBackground) {
+    private boolean handleTextQuotes(final TextView textView, final SpannableStringBuilder body, final BubbleColor bubbleColor) {
         boolean startsWithQuote = false;
         int quoteDepth = 1;
         while (QuoteHelper.bodyContainsQuoteStart(body) && quoteDepth <= Config.QUOTE_MAX_DEPTH) {
@@ -382,7 +357,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                             if (i == 0) startsWithQuote = true;
                         } else if (quoteStart >= 0) {
                             // Line start without quote, apply spans there
-                            applyQuoteSpan(body, quoteStart, i - 1, darkBackground);
+                            applyQuoteSpan(textView, body, quoteStart, i - 1, bubbleColor);
                             quoteStart = -1;
                         }
                     }
@@ -407,26 +382,19 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             }
             if (quoteStart >= 0) {
                 // Apply spans to finishing open quote
-                applyQuoteSpan(body, quoteStart, body.length(), darkBackground);
+                applyQuoteSpan(textView, body, quoteStart, body.length(), bubbleColor);
             }
             quoteDepth++;
         }
         return startsWithQuote;
     }
 
-    private void displayTextMessage(final ViewHolder viewHolder, final Message message, boolean darkBackground, int type) {
+    private void displayTextMessage(final ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor, int type) {
         viewHolder.download_button.setVisibility(View.GONE);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.messageBody.setVisibility(View.VISIBLE);
-
-        if (darkBackground) {
-            viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1_OnDark);
-        } else {
-            viewHolder.messageBody.setTextAppearance(getContext(), R.style.TextAppearance_Conversations_Body1);
-        }
-        viewHolder.messageBody.setHighlightColor(ContextCompat.getColor(activity, darkBackground
-                ? (type == SENT || !mUseGreenBackground ? R.color.black26 : R.color.grey800) : R.color.grey500));
+        setTextColor(viewHolder.messageBody, bubbleColor);
         viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
 
         if (message.getBody() != null) {
@@ -446,7 +414,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                 int end = body.getSpanEnd(mergeSeparator);
                 body.setSpan(new DividerSpan(true), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
             }
-            boolean startsWithQuote = handleTextQuotes(body, darkBackground);
+            boolean startsWithQuote = handleTextQuotes(viewHolder.messageBody, body, bubbleColor);
             if (!message.isPrivateMessage()) {
                 if (hasMeCommand) {
                     body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), 0, nick.length(),
@@ -469,7 +437,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                 } else {
                     body.insert(privateMarkerIndex, " ");
                 }
-                body.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground, false)), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                body.setSpan(new ForegroundColorSpan(bubbleToOnSurfaceVariant(viewHolder.messageBody, bubbleColor)), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                 body.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarkerIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                 if (hasMeCommand) {
                     body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarkerIndex + 1,
@@ -477,8 +445,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                 }
             }
             if (message.getConversation().getMode() == Conversation.MODE_MULTI && message.getStatus() == Message.STATUS_RECEIVED) {
-                if (message.getConversation() instanceof Conversation) {
-                    final Conversation conversation = (Conversation) message.getConversation();
+                if (message.getConversation() instanceof Conversation conversation) {
                     Pattern pattern = NotificationService.generateNickHighlightPattern(conversation.getMucOptions().getActualNick());
                     Matcher matcher = pattern.matcher(body);
                     while (matcher.find()) {
@@ -495,7 +462,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
 
             StylingHelper.format(body, viewHolder.messageBody.getCurrentTextColor());
             if (highlightedTerm != null) {
-                StylingHelper.highlight(activity, body, highlightedTerm, StylingHelper.isDarkText(viewHolder.messageBody));
+                StylingHelper.highlight(viewHolder.messageBody, body, highlightedTerm);
             }
             MyLinkify.addLinks(body, true);
             viewHolder.messageBody.setAutoLinkMask(0);
@@ -507,45 +474,54 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         }
     }
 
-    private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text, final boolean darkBackground) {
-        toggleWhisperInfo(viewHolder, message, darkBackground);
+    private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text, final BubbleColor bubbleColor) {
+        toggleWhisperInfo(viewHolder, message, bubbleColor);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.download_button.setVisibility(View.VISIBLE);
         viewHolder.download_button.setText(text);
+        final var attachment = Attachment.of(message);
+        final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
+        viewHolder.download_button.setIconResource(imageResource);
         viewHolder.download_button.setOnClickListener(v -> ConversationFragment.downloadFile(activity, message));
     }
 
-    private void displayOpenableMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
-        toggleWhisperInfo(viewHolder, message, darkBackground);
+    private void displayOpenableMessage(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
+        toggleWhisperInfo(viewHolder, message, bubbleColor);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.download_button.setVisibility(View.VISIBLE);
         viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message)));
+        final var attachment = Attachment.of(message);
+        final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
+        viewHolder.download_button.setIconResource(imageResource);
         viewHolder.download_button.setOnClickListener(v -> openDownloadable(message));
     }
 
-    private void displayLocationMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
-        toggleWhisperInfo(viewHolder, message, darkBackground);
+    private void displayLocationMessage(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
+        toggleWhisperInfo(viewHolder, message, bubbleColor);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.download_button.setVisibility(View.VISIBLE);
         viewHolder.download_button.setText(R.string.show_location);
+        final var attachment = Attachment.of(message);
+        final @DrawableRes int imageResource = MediaAdapter.getImageDrawable(attachment);
+        viewHolder.download_button.setIconResource(imageResource);
         viewHolder.download_button.setOnClickListener(v -> showLocation(message));
     }
 
-    private void displayAudioMessage(ViewHolder viewHolder, Message message, boolean darkBackground) {
-        toggleWhisperInfo(viewHolder, message, darkBackground);
+    private void displayAudioMessage(ViewHolder viewHolder, Message message, final BubbleColor bubbleColor) {
+        toggleWhisperInfo(viewHolder, message, bubbleColor);
         viewHolder.image.setVisibility(View.GONE);
         viewHolder.download_button.setVisibility(View.GONE);
         final RelativeLayout audioPlayer = viewHolder.audioPlayer;
         audioPlayer.setVisibility(View.VISIBLE);
-        AudioPlayer.ViewHolder.get(audioPlayer).setDarkBackground(darkBackground);
+        AudioPlayer.ViewHolder.get(audioPlayer).setBubbleColor(bubbleColor);
         this.audioPlayer.init(audioPlayer, message);
     }
 
-    private void displayMediaPreviewMessage(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
-        toggleWhisperInfo(viewHolder, message, darkBackground);
+    private void displayMediaPreviewMessage(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
+        toggleWhisperInfo(viewHolder, message, bubbleColor);
         viewHolder.download_button.setVisibility(View.GONE);
         viewHolder.audioPlayer.setVisibility(View.GONE);
         viewHolder.image.setVisibility(View.VISIBLE);
@@ -573,7 +549,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         viewHolder.image.setOnClickListener(v -> openDownloadable(message));
     }
 
-    private void toggleWhisperInfo(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
+    private void toggleWhisperInfo(ViewHolder viewHolder, final Message message, final BubbleColor bubbleColor) {
         if (message.isPrivateMessage()) {
             final String privateMarker;
             if (message.getStatus() <= Message.STATUS_RECEIVED) {
@@ -583,7 +559,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                 privateMarker = activity.getString(R.string.private_message_to, Strings.nullToEmpty(cp == null ? null : cp.getResource()));
             }
             final SpannableString body = new SpannableString(privateMarker);
-            body.setSpan(new ForegroundColorSpan(getMessageTextColor(darkBackground, false)), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+            body.setSpan(new ForegroundColorSpan(bubbleToOnSurfaceVariant(viewHolder.messageBody, bubbleColor)), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
             body.setSpan(new StyleSpan(Typeface.BOLD), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
             viewHolder.messageBody.setText(body);
             viewHolder.messageBody.setVisibility(View.VISIBLE);
@@ -611,7 +587,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
     }
 
     @Override
-    public View getView(int position, View view, ViewGroup parent) {
+    public View getView(final int position, View view, final @NonNull ViewGroup parent) {
         final Message message = getItem(position);
         final boolean omemoEncryption = message.getEncryption() == Message.ENCRYPTION_AXOLOTL;
         final boolean isInValidSession = message.isValidInSession() && (!omemoEncryption || message.isTrusted());
@@ -623,19 +599,18 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             viewHolder = new ViewHolder();
             switch (type) {
                 case DATE_SEPARATOR:
-                    view = activity.getLayoutInflater().inflate(R.layout.message_date_bubble, parent, false);
+                    view = activity.getLayoutInflater().inflate(R.layout.item_message_date_bubble, parent, false);
                     viewHolder.status_message = view.findViewById(R.id.message_body);
                     viewHolder.message_box = view.findViewById(R.id.message_box);
-                    viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received);
                     break;
                 case RTP_SESSION:
-                    view = activity.getLayoutInflater().inflate(R.layout.message_rtp_session, parent, false);
+                    view = activity.getLayoutInflater().inflate(R.layout.item_message_rtp_session, parent, false);
                     viewHolder.status_message = view.findViewById(R.id.message_body);
                     viewHolder.message_box = view.findViewById(R.id.message_box);
                     viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received);
                     break;
                 case SENT:
-                    view = activity.getLayoutInflater().inflate(R.layout.message_sent, parent, false);
+                    view = activity.getLayoutInflater().inflate(R.layout.item_message_sent, parent, false);
                     viewHolder.message_box = view.findViewById(R.id.message_box);
                     viewHolder.contact_picture = view.findViewById(R.id.message_photo);
                     viewHolder.download_button = view.findViewById(R.id.download_button);
@@ -648,7 +623,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                     viewHolder.audioPlayer = view.findViewById(R.id.audio_player);
                     break;
                 case RECEIVED:
-                    view = activity.getLayoutInflater().inflate(R.layout.message_received, parent, false);
+                    view = activity.getLayoutInflater().inflate(R.layout.item_message_received, parent, false);
                     viewHolder.message_box = view.findViewById(R.id.message_box);
                     viewHolder.contact_picture = view.findViewById(R.id.message_photo);
                     viewHolder.download_button = view.findViewById(R.id.download_button);
@@ -662,7 +637,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                     viewHolder.audioPlayer = view.findViewById(R.id.audio_player);
                     break;
                 case STATUS:
-                    view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false);
+                    view = activity.getLayoutInflater().inflate(R.layout.item_message_status, parent, false);
                     viewHolder.contact_picture = view.findViewById(R.id.message_photo);
                     viewHolder.status_message = view.findViewById(R.id.status_message);
                     viewHolder.load_more_messages = view.findViewById(R.id.load_more_messages);
@@ -678,7 +653,17 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             }
         }
 
-        boolean darkBackground = type == RECEIVED && (!isInValidSession || mUseGreenBackground) || activity.isDarkTheme();
+        final boolean colorfulBackground = mUseGreenBackground;
+        final BubbleColor bubbleColor;
+        if (type == RECEIVED) {
+            if (isInValidSession) {
+                bubbleColor = colorfulBackground ? BubbleColor.TERTIARY : BubbleColor.SURFACE;
+            } else {
+                bubbleColor = BubbleColor.WARNING;
+            }
+        } else {
+            bubbleColor = colorfulBackground ? BubbleColor.SECONDARY : BubbleColor.SURFACE;
+        }
 
         if (type == DATE_SEPARATOR) {
             if (UIHelper.today(message.getTimeSent())) {
@@ -688,10 +673,15 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             } else {
                 viewHolder.status_message.setText(DateUtils.formatDateTime(activity, message.getTimeSent(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR));
             }
-            viewHolder.message_box.setBackgroundResource(activity.isDarkTheme() ? R.drawable.date_bubble_grey : R.drawable.date_bubble_white);
+            if (colorfulBackground) {
+                setBackgroundTint(viewHolder.message_box,BubbleColor.PRIMARY);
+                setTextColor(viewHolder.status_message, BubbleColor.PRIMARY);
+            } else {
+                setBackgroundTint(viewHolder.message_box,BubbleColor.SURFACE);
+                setTextColor(viewHolder.status_message, BubbleColor.SURFACE);
+            }
             return view;
         } else if (type == RTP_SESSION) {
-            final boolean isDarkTheme = activity.isDarkTheme();
             final boolean received = message.getStatus() <= Message.STATUS_RECEIVED;
             final RtpSessionStatus rtpSessionStatus = RtpSessionStatus.of(message.getBody());
             final long duration = rtpSessionStatus.duration;
@@ -710,9 +700,16 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                     viewHolder.status_message.setText(activity.getString(R.string.outgoing_call_timestamp, UIHelper.readableTimeDifferenceFull(activity, message.getTimeSent())));
                 }
             }
-            viewHolder.indicatorReceived.setImageResource(RtpSessionStatus.getDrawable(received, rtpSessionStatus.successful, isDarkTheme));
-            viewHolder.indicatorReceived.setAlpha(isDarkTheme ? 0.7f : 0.57f);
-            viewHolder.message_box.setBackgroundResource(isDarkTheme ? R.drawable.date_bubble_grey : R.drawable.date_bubble_white);
+            if (colorfulBackground) {
+                setBackgroundTint(viewHolder.message_box,BubbleColor.TERTIARY);
+                setTextColor(viewHolder.status_message, BubbleColor.TERTIARY);
+                setImageTint(viewHolder.indicatorReceived, BubbleColor.TERTIARY);
+            } else {
+                setBackgroundTint(viewHolder.message_box,BubbleColor.SURFACE);
+                setTextColor(viewHolder.status_message, BubbleColor.SURFACE);
+                setImageTint(viewHolder.indicatorReceived, BubbleColor.SURFACE);
+            }
+            viewHolder.indicatorReceived.setImageResource(RtpSessionStatus.getDrawable(received, rtpSessionStatus.successful));
             return view;
         } else if (type == STATUS) {
             if ("LOAD_MORE".equals(message.getBody())) {
@@ -769,43 +766,43 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         final boolean unInitiatedButKnownSize = MessageUtils.unInitiatedButKnownSize(message);
         if (unInitiatedButKnownSize || message.isDeleted() || (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING)) {
             if (unInitiatedButKnownSize || transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER) {
-                displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)), darkBackground);
+                displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message)), bubbleColor);
             } else if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) {
-                displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)), darkBackground);
+                displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message)), bubbleColor);
             } else {
-                displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, darkBackground);
+                displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, bubbleColor);
             }
         } else if (message.isFileOrImage() && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) {
             if (message.getFileParams().width > 0 && message.getFileParams().height > 0) {
-                displayMediaPreviewMessage(viewHolder, message, darkBackground);
+                displayMediaPreviewMessage(viewHolder, message, bubbleColor);
             } else if (message.getFileParams().runtime > 0) {
-                displayAudioMessage(viewHolder, message, darkBackground);
+                displayAudioMessage(viewHolder, message, bubbleColor);
             } else {
-                displayOpenableMessage(viewHolder, message, darkBackground);
+                displayOpenableMessage(viewHolder, message, bubbleColor);
             }
         } else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
             if (account.isPgpDecryptionServiceConnected()) {
                 if (conversation instanceof Conversation && !account.hasPendingPgpIntent((Conversation) conversation)) {
-                    displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), darkBackground);
+                    displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), bubbleColor);
                 } else {
-                    displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), darkBackground);
+                    displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), bubbleColor);
                 }
             } else {
-                displayInfoMessage(viewHolder, activity.getString(R.string.install_openkeychain), darkBackground);
+                displayInfoMessage(viewHolder, activity.getString(R.string.install_openkeychain), bubbleColor);
                 viewHolder.message_box.setOnClickListener(this::promptOpenKeychainInstall);
                 viewHolder.messageBody.setOnClickListener(this::promptOpenKeychainInstall);
             }
         } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
-            displayInfoMessage(viewHolder, activity.getString(R.string.decryption_failed), darkBackground);
+            displayInfoMessage(viewHolder, activity.getString(R.string.decryption_failed), bubbleColor);
         } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE) {
-            displayInfoMessage(viewHolder, activity.getString(R.string.not_encrypted_for_this_device), darkBackground);
+            displayInfoMessage(viewHolder, activity.getString(R.string.not_encrypted_for_this_device), bubbleColor);
         } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_FAILED) {
-            displayInfoMessage(viewHolder, activity.getString(R.string.omemo_decryption_failed), darkBackground);
+            displayInfoMessage(viewHolder, activity.getString(R.string.omemo_decryption_failed), bubbleColor);
         } else {
             if (message.isGeoUri()) {
-                displayLocationMessage(viewHolder, message, darkBackground);
+                displayLocationMessage(viewHolder, message, bubbleColor);
             } else if (message.bodyIsOnlyEmojis() && message.getType() != Message.TYPE_PRIVATE) {
-                displayEmojiMessage(viewHolder, message.getBody().trim(), darkBackground);
+                displayEmojiMessage(viewHolder, message.getBody().trim(), bubbleColor);
             } else if (message.treatAsDownloadable()) {
                 try {
                     final URI uri = new URI(message.getBody());
@@ -814,31 +811,27 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                             activity.getString(R.string.check_x_filesize_on_host,
                                     UIHelper.getFileDescriptionString(activity, message),
                                     uri.getHost()),
-                            darkBackground);
+                            bubbleColor);
                 } catch (Exception e) {
                     displayDownloadableMessage(viewHolder,
                             message,
                             activity.getString(R.string.check_x_filesize,
                                     UIHelper.getFileDescriptionString(activity, message)),
-                            darkBackground);
+                            bubbleColor);
                 }
             } else {
-                displayTextMessage(viewHolder, message, darkBackground, type);
+                displayTextMessage(viewHolder, message, bubbleColor, type);
             }
         }
 
+        setBackgroundTint(viewHolder.message_box, bubbleColor);
+        setTextColor(viewHolder.messageBody, bubbleColor);
+
         if (type == RECEIVED) {
+            setTextColor(viewHolder.encryption, bubbleColor);
             if (isInValidSession) {
-                int bubble;
-                if (!mUseGreenBackground) {
-                    bubble = activity.getThemeResource(R.attr.message_bubble_received_monochrome, R.drawable.message_bubble_received_white);
-                } else {
-                    bubble = activity.getThemeResource(R.attr.message_bubble_received_green, R.drawable.message_bubble_received);
-                }
-                viewHolder.message_box.setBackgroundResource(bubble);
                 viewHolder.encryption.setVisibility(View.GONE);
             } else {
-                viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_warning);
                 viewHolder.encryption.setVisibility(View.VISIBLE);
                 if (omemoEncryption && !message.isTrusted()) {
                     viewHolder.encryption.setText(R.string.not_trusted);
@@ -848,7 +841,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
             }
         }
 
-        displayStatus(viewHolder, message, type, darkBackground);
+        displayStatus(viewHolder, message, type, bubbleColor);
 
         return view;
     }
@@ -911,13 +904,68 @@ public class MessageAdapter extends ArrayAdapter<Message> {
         void onContactPictureLongClicked(View v, Message message);
     }
 
+    private static void setBackgroundTint(final View view, final BubbleColor bubbleColor) {
+        view.setBackgroundTintList(bubbleToColorStateList(view, bubbleColor));
+    }
+
+    private static ColorStateList bubbleToColorStateList(final View view, final BubbleColor bubbleColor) {
+        final @AttrRes int colorAttributeResId = switch (bubbleColor) {
+            case SURFACE ->  com.google.android.material.R.attr.colorSurfaceContainerHigh;
+            case PRIMARY -> com.google.android.material.R.attr.colorPrimaryContainer;
+            case SECONDARY -> com.google.android.material.R.attr.colorSecondaryContainer;
+            case TERTIARY -> com.google.android.material.R.attr.colorTertiaryContainer;
+            case WARNING -> com.google.android.material.R.attr.colorErrorContainer;
+        };
+        return ColorStateList.valueOf(MaterialColors.getColor(view,colorAttributeResId));
+    }
+
+    public static void setImageTint(final ImageView imageView, final BubbleColor bubbleColor) {
+        ImageViewCompat.setImageTintList(imageView,bubbleToOnSurfaceColorStateList(imageView, bubbleColor));
+    }
+
+    public static void setTextColor(final TextView textView, final BubbleColor bubbleColor) {
+        textView.setTextColor(bubbleToOnSurfaceColor(textView, bubbleColor));
+    }
+
+    private static @ColorInt int bubbleToOnSurfaceVariant(final View view, final BubbleColor bubbleColor) {
+        final @AttrRes int colorAttributeResId;
+        if (bubbleColor == BubbleColor.SURFACE) {
+            colorAttributeResId = com.google.android.material.R.attr.colorOnSurfaceVariant;
+        } else {
+            colorAttributeResId = bubbleToOnSurface(bubbleColor);
+        }
+        return MaterialColors.getColor(view,colorAttributeResId);
+    }
+
+    private static @ColorInt int bubbleToOnSurfaceColor(final View view, final BubbleColor bubbleColor) {
+        return MaterialColors.getColor(view, bubbleToOnSurface(bubbleColor));
+    }
+
+    public static ColorStateList bubbleToOnSurfaceColorStateList(final View view, final BubbleColor bubbleColor) {
+        return ColorStateList.valueOf(bubbleToOnSurfaceColor(view, bubbleColor));
+    }
+
+    private static @AttrRes int bubbleToOnSurface(final BubbleColor bubbleColor) {
+        return switch (bubbleColor) {
+            case SURFACE ->  com.google.android.material.R.attr.colorOnSurface;
+            case PRIMARY -> com.google.android.material.R.attr.colorOnPrimaryContainer;
+            case SECONDARY -> com.google.android.material.R.attr.colorOnSecondaryContainer;
+            case TERTIARY -> com.google.android.material.R.attr.colorOnTertiaryContainer;
+            case WARNING -> com.google.android.material.R.attr.colorOnErrorContainer;
+        };
+    }
+
+    public  enum BubbleColor {
+        SURFACE, PRIMARY, SECONDARY, TERTIARY, WARNING
+    }
+
     private static class ViewHolder {
 
-        public Button load_more_messages;
+        public MaterialButton load_more_messages;
         public ImageView edit_indicator;
         public RelativeLayout audioPlayer;
         protected LinearLayout message_box;
-        protected Button download_button;
+        protected MaterialButton download_button;
         protected ImageView image;
         protected ImageView indicator;
         protected ImageView indicatorReceived;

src/main/java/eu/siacs/conversations/ui/adapter/UserAdapter.java 🔗

@@ -17,7 +17,7 @@ import org.openintents.openpgp.util.OpenPgpUtils;
 
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.PgpEngine;
-import eu.siacs.conversations.databinding.ContactBinding;
+import eu.siacs.conversations.databinding.ItemContactBinding;
 import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.MucOptions;
 import eu.siacs.conversations.services.XmppConnectionService;
@@ -62,7 +62,7 @@ public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHo
     @NonNull
     @Override
     public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
-        return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.contact, viewGroup, false));
+        return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.item_contact, viewGroup, false));
     }
 
     @Override
@@ -129,11 +129,11 @@ public class UserAdapter extends ListAdapter<MucOptions.User, UserAdapter.ViewHo
         MucDetailsContextMenuHelper.onCreateContextMenu(menu,v);
     }
 
-    class ViewHolder extends RecyclerView.ViewHolder {
+    static class ViewHolder extends RecyclerView.ViewHolder {
 
-        private final ContactBinding binding;
+        private final ItemContactBinding binding;
 
-        private ViewHolder(ContactBinding binding) {
+        private ViewHolder(ItemContactBinding binding) {
             super(binding.getRoot());
             this.binding = binding;
         }

src/main/java/eu/siacs/conversations/ui/adapter/UserPreviewAdapter.java 🔗

@@ -11,13 +11,14 @@ import androidx.recyclerview.widget.ListAdapter;
 import androidx.recyclerview.widget.RecyclerView;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.UserPreviewBinding;
+import eu.siacs.conversations.databinding.ItemUserPreviewBinding;
 import eu.siacs.conversations.entities.MucOptions;
 import eu.siacs.conversations.ui.XmppActivity;
 import eu.siacs.conversations.ui.util.AvatarWorkerTask;
 import eu.siacs.conversations.ui.util.MucDetailsContextMenuHelper;
 
-public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreviewAdapter.ViewHolder> implements View.OnCreateContextMenuListener {
+public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreviewAdapter.ViewHolder>
+        implements View.OnCreateContextMenuListener {
 
     private MucOptions.User selectedUser = null;
 
@@ -28,29 +29,43 @@ public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreview
     @NonNull
     @Override
     public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
-        return new ViewHolder(DataBindingUtil.inflate(LayoutInflater.from(viewGroup.getContext()), R.layout.user_preview, viewGroup, false));
+        return new ViewHolder(
+                DataBindingUtil.inflate(
+                        LayoutInflater.from(viewGroup.getContext()),
+                        R.layout.item_user_preview,
+                        viewGroup,
+                        false));
     }
 
     @Override
     public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
         final MucOptions.User user = getItem(position);
         AvatarWorkerTask.loadAvatar(user, viewHolder.binding.avatar, R.dimen.media_size);
-        viewHolder.binding.getRoot().setOnClickListener(v -> {
-            final XmppActivity activity = XmppActivity.find(v);
-            if (activity != null) {
-                activity.highlightInMuc(user.getConversation(), user.getName());
-            }
-        });
+        viewHolder
+                .binding
+                .getRoot()
+                .setOnClickListener(
+                        v -> {
+                            final XmppActivity activity = XmppActivity.find(v);
+                            if (activity != null) {
+                                activity.highlightInMuc(user.getConversation(), user.getName());
+                            }
+                        });
         viewHolder.binding.getRoot().setOnCreateContextMenuListener(this);
         viewHolder.binding.getRoot().setTag(user);
-        viewHolder.binding.getRoot().setOnLongClickListener(v -> {
-            selectedUser = user;
-            return false;
-        });
+        viewHolder
+                .binding
+                .getRoot()
+                .setOnLongClickListener(
+                        v -> {
+                            selectedUser = user;
+                            return false;
+                        });
     }
 
     @Override
-    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+    public void onCreateContextMenu(
+            ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
         MucDetailsContextMenuHelper.onCreateContextMenu(menu, v);
     }
 
@@ -60,9 +75,9 @@ public class UserPreviewAdapter extends ListAdapter<MucOptions.User, UserPreview
 
     class ViewHolder extends RecyclerView.ViewHolder {
 
-        private final UserPreviewBinding binding;
+        private final ItemUserPreviewBinding binding;
 
-        private ViewHolder(UserPreviewBinding binding) {
+        private ViewHolder(final ItemUserPreviewBinding binding) {
             super(binding.getRoot());
             this.binding = binding;
         }

src/main/java/eu/siacs/conversations/ui/forms/FormBooleanFieldWrapper.java 🔗

@@ -1,80 +0,0 @@
-package eu.siacs.conversations.ui.forms;
-
-import android.content.Context;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.xmpp.forms.Field;
-
-public class FormBooleanFieldWrapper extends FormFieldWrapper {
-
-	protected CheckBox checkBox;
-
-	protected FormBooleanFieldWrapper(Context context, Field field) {
-		super(context, field);
-		checkBox = view.findViewById(R.id.field);
-		checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-			@Override
-			public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-				checkBox.setError(null);
-				invokeOnFormFieldValuesEdited();
-			}
-		});
-	}
-
-	@Override
-	protected void setLabel(String label, boolean required) {
-		CheckBox checkBox = view.findViewById(R.id.field);
-		checkBox.setText(createSpannableLabelString(label, required));
-	}
-
-	@Override
-	public List<String> getValues() {
-		List<String> values = new ArrayList<>();
-		values.add(Boolean.toString(checkBox.isChecked()));
-		return values;
-	}
-
-	@Override
-	protected void setValues(List<String> values) {
-		if (values.size() == 0) {
-			checkBox.setChecked(false);
-		} else {
-			checkBox.setChecked(Boolean.parseBoolean(values.get(0)));
-		}
-	}
-
-	@Override
-	public boolean validates() {
-		if (checkBox.isChecked() || !field.isRequired()) {
-			return true;
-		} else {
-			checkBox.setError(context.getString(R.string.this_field_is_required));
-			checkBox.requestFocus();
-			return false;
-		}
-	}
-
-	@Override
-	public boolean edited() {
-		if (field.getValues().size() == 0) {
-			return checkBox.isChecked();
-		} else {
-			return super.edited();
-		}
-	}
-
-	@Override
-	protected int getLayoutResource() {
-		return R.layout.form_boolean;
-	}
-
-	@Override
-	void setReadOnly(boolean readOnly) {
-		checkBox.setEnabled(!readOnly);
-	}
-}

src/main/java/eu/siacs/conversations/ui/forms/FormFieldFactory.java 🔗

@@ -1,30 +0,0 @@
-package eu.siacs.conversations.ui.forms;
-
-import android.content.Context;
-
-import java.util.Hashtable;
-
-import eu.siacs.conversations.xmpp.forms.Field;
-
-
-
-public class FormFieldFactory {
-
-	private static final Hashtable<String, Class> typeTable = new Hashtable<>();
-
-	static {
-		typeTable.put("text-single", FormTextFieldWrapper.class);
-		typeTable.put("text-multi", FormTextFieldWrapper.class);
-		typeTable.put("text-private", FormTextFieldWrapper.class);
-		typeTable.put("jid-single", FormJidSingleFieldWrapper.class);
-		typeTable.put("boolean", FormBooleanFieldWrapper.class);
-	}
-
-	protected static FormFieldWrapper createFromField(Context context, Field field) {
-		Class clazz = typeTable.get(field.getType());
-		if (clazz == null) {
-			clazz = FormTextFieldWrapper.class;
-		}
-		return FormFieldWrapper.createFromField(clazz, context, field);
-	}
-}

src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java 🔗

@@ -1,93 +0,0 @@
-package eu.siacs.conversations.ui.forms;
-
-import android.content.Context;
-import android.text.SpannableString;
-import android.text.style.ForegroundColorSpan;
-import android.text.style.StyleSpan;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import java.util.List;
-
-import eu.siacs.conversations.ui.util.StyledAttributes;
-import eu.siacs.conversations.xmpp.forms.Field;
-
-public abstract class FormFieldWrapper {
-
-	protected final Context context;
-	protected final Field field;
-	protected final View view;
-	OnFormFieldValuesEdited onFormFieldValuesEditedListener;
-
-	FormFieldWrapper(Context context, Field field) {
-		this.context = context;
-		this.field = field;
-		LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-		this.view = inflater.inflate(getLayoutResource(), null);
-		String label = field.getLabel();
-		if (label == null) {
-			label = field.getFieldName();
-		}
-		setLabel(label, field.isRequired());
-	}
-
-	public final void submit() {
-		this.field.setValues(getValues());
-	}
-
-	public final View getView() {
-		return view;
-	}
-
-	protected abstract void setLabel(String label, boolean required);
-
-	abstract List<String> getValues();
-
-	protected abstract void setValues(List<String> values);
-
-	abstract boolean validates();
-
-	abstract protected int getLayoutResource();
-
-	abstract void setReadOnly(boolean readOnly);
-
-	protected SpannableString createSpannableLabelString(String label, boolean required) {
-		SpannableString spannableString = new SpannableString(label + (required ? " *" : ""));
-		if (required) {
-			int start = label.length();
-			int end = label.length() + 2;
-			spannableString.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), start, end, 0);
-			spannableString.setSpan(new ForegroundColorSpan(StyledAttributes.getColor(context, androidx.appcompat.R.attr.colorAccent)), start, end, 0);
-		}
-		return spannableString;
-	}
-
-	protected void invokeOnFormFieldValuesEdited() {
-		if (this.onFormFieldValuesEditedListener != null) {
-			this.onFormFieldValuesEditedListener.onFormFieldValuesEdited();
-		}
-	}
-
-	public boolean edited() {
-		return !field.getValues().equals(getValues());
-	}
-
-	public void setOnFormFieldValuesEditedListener(OnFormFieldValuesEdited listener) {
-		this.onFormFieldValuesEditedListener = listener;
-	}
-
-	protected static <F extends FormFieldWrapper> FormFieldWrapper createFromField(Class<F> c, Context context, Field field) {
-		try {
-			F fieldWrapper = c.getDeclaredConstructor(Context.class, Field.class).newInstance(context,field);
-			fieldWrapper.setValues(field.getValues());
-			return fieldWrapper;
-		} catch (Exception e) {
-			e.printStackTrace();
-			return null;
-		}
-	}
-
-	public interface OnFormFieldValuesEdited {
-		void onFormFieldValuesEdited();
-	}
-}

src/main/java/eu/siacs/conversations/ui/forms/FormJidSingleFieldWrapper.java 🔗

@@ -1,43 +0,0 @@
-package eu.siacs.conversations.ui.forms;
-
-import android.content.Context;
-import android.text.InputType;
-
-import java.util.List;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.xmpp.Jid;
-import eu.siacs.conversations.xmpp.forms.Field;
-
-public class FormJidSingleFieldWrapper extends FormTextFieldWrapper {
-
-	protected FormJidSingleFieldWrapper(Context context, Field field) {
-		super(context, field);
-		editText.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
-		editText.setHint(R.string.account_settings_example_jabber_id);
-	}
-
-	@Override
-	public boolean validates() {
-		String value = getValue();
-		if (!value.isEmpty()) {
-			try {
-				Jid.of(value);
-			} catch (IllegalArgumentException e) {
-				editText.setError(context.getString(R.string.invalid_jid));
-				editText.requestFocus();
-				return false;
-			}
-		}
-		return super.validates();
-	}
-
-	@Override
-	protected void setValues(List<String> values) {
-		StringBuilder builder = new StringBuilder();
-		for(String value : values) {
-			builder.append(value);
-		}
-		editText.setText(builder.toString());
-	}
-}

src/main/java/eu/siacs/conversations/ui/forms/FormTextFieldWrapper.java 🔗

@@ -1,97 +0,0 @@
-package eu.siacs.conversations.ui.forms;
-
-import android.content.Context;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextWatcher;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.xmpp.forms.Field;
-
-public class FormTextFieldWrapper extends FormFieldWrapper {
-
-	protected EditText editText;
-
-	protected FormTextFieldWrapper(Context context, Field field) {
-		super(context, field);
-		editText = view.findViewById(R.id.field);
-		editText.setSingleLine(!"text-multi".equals(field.getType()));
-		if ("text-private".equals(field.getType())) {
-			editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
-		}
-		editText.addTextChangedListener(new TextWatcher() {
-			@Override
-			public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-			}
-
-			@Override
-			public void onTextChanged(CharSequence s, int start, int before, int count) {
-				editText.setError(null);
-				invokeOnFormFieldValuesEdited();
-			}
-
-			@Override
-			public void afterTextChanged(Editable s) {
-			}
-		});
-	}
-
-	@Override
-	protected void setLabel(String label, boolean required) {
-		TextView textView = view.findViewById(R.id.label);
-		textView.setText(createSpannableLabelString(label, required));
-	}
-
-	protected String getValue() {
-		return editText.getText().toString();
-	}
-
-	@Override
-	public List<String> getValues() {
-		List<String> values = new ArrayList<>();
-		for (String line : getValue().split("\\n")) {
-			if (line.length() > 0) {
-				values.add(line);
-			}
-		}
-		return values;
-	}
-
-	@Override
-	protected void setValues(List<String> values) {
-		StringBuilder builder = new StringBuilder();
-		for(int i = 0; i < values.size(); ++i) {
-			builder.append(values.get(i));
-			if (i < values.size() - 1 && "text-multi".equals(field.getType())) {
-				builder.append("\n");
-			}
-		}
-		editText.setText(builder.toString());
-	}
-
-	@Override
-	public boolean validates() {
-		if (getValue().trim().length() > 0 || !field.isRequired()) {
-			return true;
-		} else {
-			editText.setError(context.getString(R.string.this_field_is_required));
-			editText.requestFocus();
-			return false;
-		}
-	}
-
-	@Override
-	protected int getLayoutResource() {
-		return R.layout.form_text;
-	}
-
-	@Override
-	void setReadOnly(boolean readOnly) {
-		editText.setEnabled(!readOnly);
-	}
-}

src/main/java/eu/siacs/conversations/ui/forms/FormWrapper.java 🔗

@@ -1,72 +0,0 @@
-package eu.siacs.conversations.ui.forms;
-
-import android.content.Context;
-import android.widget.LinearLayout;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import eu.siacs.conversations.xmpp.forms.Data;
-import eu.siacs.conversations.xmpp.forms.Field;
-
-public class FormWrapper {
-
-	private final LinearLayout layout;
-
-	private final Data form;
-
-	private final List<FormFieldWrapper> fieldWrappers = new ArrayList<>();
-
-	private FormWrapper(Context context, LinearLayout linearLayout, Data form) {
-		this.form = form;
-		this.layout = linearLayout;
-		this.layout.removeAllViews();
-		for(Field field : form.getFields()) {
-			FormFieldWrapper fieldWrapper = FormFieldFactory.createFromField(context,field);
-			if (fieldWrapper != null) {
-				layout.addView(fieldWrapper.getView());
-				fieldWrappers.add(fieldWrapper);
-			}
-		}
-	}
-
-	public Data submit() {
-		for(FormFieldWrapper fieldWrapper : fieldWrappers) {
-			fieldWrapper.submit();
-		}
-		this.form.submit();
-		return this.form;
-	}
-
-	public boolean validates() {
-		boolean validates = true;
-		for(FormFieldWrapper fieldWrapper : fieldWrappers) {
-			validates &= fieldWrapper.validates();
-		}
-		return validates;
-	}
-
-	public void setOnFormFieldValuesEditedListener(FormFieldWrapper.OnFormFieldValuesEdited listener) {
-		for(FormFieldWrapper fieldWrapper : fieldWrappers) {
-			fieldWrapper.setOnFormFieldValuesEditedListener(listener);
-		}
-	}
-
-	public void setReadOnly(boolean b) {
-		for(FormFieldWrapper fieldWrapper : fieldWrappers) {
-			fieldWrapper.setReadOnly(b);
-		}
-	}
-
-	public boolean edited() {
-		boolean edited = false;
-		for(FormFieldWrapper fieldWrapper : fieldWrappers) {
-			edited |= fieldWrapper.edited();
-		}
-		return edited;
-	}
-
-	public static FormWrapper createInLayout(Context context, LinearLayout layout, Data form) {
-		return new FormWrapper(context, layout, form);
-	}
-}

src/main/java/eu/siacs/conversations/ui/service/AudioPlayer.java 🔗

@@ -22,11 +22,6 @@ import android.widget.TextView;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
 
-import java.lang.ref.WeakReference;
-import java.util.Locale;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Message;
@@ -36,7 +31,17 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter;
 import eu.siacs.conversations.ui.util.PendingItem;
 import eu.siacs.conversations.utils.WeakReferenceSet;
 
-public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompletionListener, SeekBar.OnSeekBarChangeListener, Runnable, SensorEventListener {
+import java.lang.ref.WeakReference;
+import java.util.Locale;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class AudioPlayer
+        implements View.OnClickListener,
+                MediaPlayer.OnCompletionListener,
+                SeekBar.OnSeekBarChangeListener,
+                Runnable,
+                SensorEventListener {
 
     private static final int REFRESH_INTERVAL = 250;
     private static final Object LOCK = new Object();
@@ -57,33 +62,43 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
         final Context context = adapter.getContext();
         this.messageAdapter = adapter;
         this.sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
-        this.proximitySensor = this.sensorManager == null ? null : this.sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+        this.proximitySensor =
+                this.sensorManager == null
+                        ? null
+                        : this.sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
         initializeProximityWakeLock(context);
         synchronized (AudioPlayer.LOCK) {
             if (AudioPlayer.player != null) {
                 AudioPlayer.player.setOnCompletionListener(this);
                 if (AudioPlayer.player.isPlaying() && sensorManager != null) {
-                    sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+                    sensorManager.registerListener(
+                            this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
                 }
             }
         }
     }
 
     private static String formatTime(int ms) {
-        return String.format(Locale.ENGLISH, "%d:%02d", ms / 60000, Math.min(Math.round((ms % 60000) / 1000f), 59));
+        return String.format(
+                Locale.ENGLISH,
+                "%d:%02d",
+                ms / 60000,
+                Math.min(Math.round((ms % 60000) / 1000f), 59));
     }
 
     private void initializeProximityWakeLock(Context context) {
-        if (Build.VERSION.SDK_INT >= 21) {
-            synchronized (AudioPlayer.LOCK) {
-                if (AudioPlayer.wakeLock == null) {
-                    final PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-                    AudioPlayer.wakeLock = powerManager == null ? null : powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, AudioPlayer.class.getSimpleName());
-                    AudioPlayer.wakeLock.setReferenceCounted(false);
-                }
+        synchronized (AudioPlayer.LOCK) {
+            if (AudioPlayer.wakeLock == null) {
+                final PowerManager powerManager =
+                        (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+                AudioPlayer.wakeLock =
+                        powerManager == null
+                                ? null
+                                : powerManager.newWakeLock(
+                                        PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
+                                        AudioPlayer.class.getSimpleName());
+                AudioPlayer.wakeLock.setReferenceCounted(false);
             }
-        } else {
-            AudioPlayer.wakeLock = null;
         }
     }
 
@@ -92,41 +107,39 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
             audioPlayer.setTag(message);
             if (init(ViewHolder.get(audioPlayer), message)) {
                 this.audioPlayerLayouts.addWeakReferenceTo(audioPlayer);
-                executor.execute(()-> this.stopRefresher(true));
+                executor.execute(() -> this.stopRefresher(true));
             } else {
                 this.audioPlayerLayouts.removeWeakReferenceTo(audioPlayer);
             }
         }
     }
 
-    private boolean init(ViewHolder viewHolder, Message message) {
-        if (viewHolder.darkBackground) {
-            viewHolder.runtime.setTextAppearance(this.messageAdapter.getContext(), R.style.TextAppearance_Conversations_Caption_OnDark);
-        } else {
-            viewHolder.runtime.setTextAppearance(this.messageAdapter.getContext(), R.style.TextAppearance_Conversations_Caption);
-        }
+    private boolean init(final ViewHolder viewHolder, final Message message) {
+        MessageAdapter.setTextColor(viewHolder.runtime, viewHolder.bubbleColor);
         viewHolder.progress.setOnSeekBarChangeListener(this);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            ColorStateList color = ContextCompat.getColorStateList(messageAdapter.getContext(), viewHolder.darkBackground ? R.color.white70 : R.color.green700_desaturated);
-            viewHolder.progress.setThumbTintList(color);
-            viewHolder.progress.setProgressTintList(color);
-        }
-        viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f);
+        final ColorStateList color =
+                MessageAdapter.bubbleToOnSurfaceColorStateList(
+                        viewHolder.progress, viewHolder.bubbleColor);
+        viewHolder.progress.setThumbTintList(color);
+        viewHolder.progress.setProgressTintList(color);
         viewHolder.playPause.setOnClickListener(this);
         final Context context = viewHolder.playPause.getContext();
         if (message == currentlyPlayingMessage) {
             if (AudioPlayer.player != null && AudioPlayer.player.isPlaying()) {
-                viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
+                viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
+                MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
                 viewHolder.playPause.setContentDescription(context.getString(R.string.pause_audio));
                 viewHolder.progress.setEnabled(true);
             } else {
                 viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
-                viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
+                viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
+                MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
                 viewHolder.progress.setEnabled(false);
             }
             return true;
         } else {
-            viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
+            viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
+            MessageAdapter.setImageTint(viewHolder.playPause, viewHolder.bubbleColor);
             viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
             viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
             viewHolder.progress.setProgress(0);
@@ -145,9 +158,16 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
     }
 
     private void startStop(ImageButton playPause) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission(messageAdapter.getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU
+                && ContextCompat.checkSelfPermission(
+                                messageAdapter.getActivity(),
+                                Manifest.permission.WRITE_EXTERNAL_STORAGE)
+                        != PackageManager.PERMISSION_GRANTED) {
             pendingOnClickView.push(new WeakReference<>(playPause));
-            ActivityCompat.requestPermissions(messageAdapter.getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, ConversationsActivity.REQUEST_PLAY_PAUSE);
+            ActivityCompat.requestPermissions(
+                    messageAdapter.getActivity(),
+                    new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
+                    ConversationsActivity.REQUEST_PLAY_PAUSE);
             return;
         }
         initializeProximityWakeLock(playPause.getContext());
@@ -163,13 +183,13 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
 
     private boolean playPauseCurrent(final ViewHolder viewHolder) {
         final Context context = viewHolder.playPause.getContext();
-        viewHolder.playPause.setAlpha(viewHolder.darkBackground ? 0.7f : 0.57f);
         if (player.isPlaying()) {
             viewHolder.progress.setEnabled(false);
             player.pause();
             messageAdapter.flagScreenOff();
             releaseProximityWakeLock();
-            viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
+            viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
+            MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
             viewHolder.playPause.setContentDescription(context.getString(R.string.play_audio));
         } else {
             viewHolder.progress.setEnabled(true);
@@ -177,7 +197,8 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
             messageAdapter.flagScreenOn();
             acquireProximityWakeLock();
             this.stopRefresher(true);
-            viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
+            viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
+            MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
             viewHolder.playPause.setContentDescription(context.getString(R.string.pause_audio));
         }
         return false;
@@ -193,19 +214,24 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
         AudioPlayer.player = new MediaPlayer();
         try {
             AudioPlayer.currentlyPlayingMessage = message;
-            AudioPlayer.player.setAudioStreamType(earpiece ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC);
-            AudioPlayer.player.setDataSource(messageAdapter.getFileBackend().getFile(message).getAbsolutePath());
+            AudioPlayer.player.setAudioStreamType(
+                    earpiece ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC);
+            AudioPlayer.player.setDataSource(
+                    messageAdapter.getFileBackend().getFile(message).getAbsolutePath());
             AudioPlayer.player.setOnCompletionListener(this);
             AudioPlayer.player.prepare();
             AudioPlayer.player.start();
             messageAdapter.flagScreenOn();
             acquireProximityWakeLock();
             viewHolder.progress.setEnabled(true);
-            viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_pause_white_36dp : R.drawable.ic_pause_black_36dp);
-            viewHolder.playPause.setContentDescription(viewHolder.playPause.getContext().getString(R.string.pause_audio));
-            sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
+            viewHolder.playPause.setImageResource(R.drawable.ic_pause_24dp);
+            MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
+            viewHolder.playPause.setContentDescription(
+                    viewHolder.playPause.getContext().getString(R.string.pause_audio));
+            sensorManager.registerListener(
+                    this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
             return true;
-        } catch (Exception e) {
+        } catch (final Exception e) {
             messageAdapter.flagScreenOff();
             releaseProximityWakeLock();
             AudioPlayer.currentlyPlayingMessage = null;
@@ -251,14 +277,16 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
         }
     }
 
-    private void resetPlayerUi(RelativeLayout audioPlayer) {
+    private void resetPlayerUi(final RelativeLayout audioPlayer) {
         if (audioPlayer == null) {
             return;
         }
         final ViewHolder viewHolder = ViewHolder.get(audioPlayer);
         final Message message = (Message) audioPlayer.getTag();
-        viewHolder.playPause.setContentDescription(viewHolder.playPause.getContext().getString(R.string.play_audio));
-        viewHolder.playPause.setImageResource(viewHolder.darkBackground ? R.drawable.ic_play_arrow_white_36dp : R.drawable.ic_play_arrow_black_36dp);
+        viewHolder.playPause.setContentDescription(
+                viewHolder.playPause.getContext().getString(R.string.play_audio));
+        viewHolder.playPause.setImageResource(R.drawable.ic_play_arrow_24dp);
+        MessageAdapter.setImageTint(viewHolder.playPause,viewHolder.bubbleColor);
         if (message != null) {
             viewHolder.runtime.setText(formatTime(message.getFileParams().runtime));
         }
@@ -297,14 +325,10 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
     }
 
     @Override
-    public void onStartTrackingTouch(SeekBar seekBar) {
-
-    }
+    public void onStartTrackingTouch(SeekBar seekBar) {}
 
     @Override
-    public void onStopTrackingTouch(SeekBar seekBar) {
-
-    }
+    public void onStopTrackingTouch(SeekBar seekBar) {}
 
     public void stop() {
         synchronized (AudioPlayer.LOCK) {
@@ -361,7 +385,8 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
         } else {
             viewHolder.progress.setProgress(current * 100 / duration);
         }
-        viewHolder.runtime.setText(String.format("%s / %s", formatTime(current), formatTime(duration)));
+        viewHolder.runtime.setText(
+                String.format("%s / %s", formatTime(current), formatTime(duration)));
         return true;
     }
 
@@ -391,7 +416,11 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
                 try {
                     ViewHolder currentViewHolder = getCurrentViewHolder();
                     if (currentViewHolder != null) {
-                        play(currentViewHolder, currentlyPlayingMessage, streamType == AudioManager.STREAM_VOICE_CALL, progress);
+                        play(
+                                currentViewHolder,
+                                currentlyPlayingMessage,
+                                streamType == AudioManager.STREAM_VOICE_CALL,
+                                progress);
                     }
                 } catch (Exception e) {
                     Log.w(Config.LOGTAG, e);
@@ -401,8 +430,7 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
     }
 
     @Override
-    public void onAccuracyChanged(Sensor sensor, int i) {
-    }
+    public void onAccuracyChanged(Sensor sensor, int i) {}
 
     private void acquireProximityWakeLock() {
         synchronized (AudioPlayer.LOCK) {
@@ -435,22 +463,24 @@ public class AudioPlayer implements View.OnClickListener, MediaPlayer.OnCompleti
         private TextView runtime;
         private SeekBar progress;
         private ImageButton playPause;
-        private boolean darkBackground = false;
-
-        public static ViewHolder get(RelativeLayout audioPlayer) {
-            ViewHolder viewHolder = (ViewHolder) audioPlayer.getTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER);
-            if (viewHolder == null) {
-                viewHolder = new ViewHolder();
-                viewHolder.runtime = audioPlayer.findViewById(R.id.runtime);
-                viewHolder.progress = audioPlayer.findViewById(R.id.progress);
-                viewHolder.playPause = audioPlayer.findViewById(R.id.play_pause);
-                audioPlayer.setTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER, viewHolder);
+        private MessageAdapter.BubbleColor bubbleColor = MessageAdapter.BubbleColor.SURFACE;
+
+        public static ViewHolder get(final RelativeLayout audioPlayer) {
+            final var existingViewHolder =
+                    (ViewHolder) audioPlayer.getTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER);
+            if (existingViewHolder != null) {
+                return existingViewHolder;
             }
+            final ViewHolder viewHolder = new ViewHolder();
+            viewHolder.runtime = audioPlayer.findViewById(R.id.runtime);
+            viewHolder.progress = audioPlayer.findViewById(R.id.progress);
+            viewHolder.playPause = audioPlayer.findViewById(R.id.play_pause);
+            audioPlayer.setTag(R.id.TAG_AUDIO_PLAYER_VIEW_HOLDER, viewHolder);
             return viewHolder;
         }
 
-        public void setDarkBackground(boolean darkBackground) {
-            this.darkBackground = darkBackground;
+        public void setBubbleColor(final MessageAdapter.BubbleColor bubbleColor) {
+            this.bubbleColor = bubbleColor;
         }
     }
 }

src/main/java/eu/siacs/conversations/ui/util/ActionBarUtil.java 🔗

@@ -1,88 +0,0 @@
-package eu.siacs.conversations.ui.util;
-
-import android.content.Context;
-import android.view.View;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.lang.reflect.Field;
-
-public class ActionBarUtil {
-
-    public static void resetActionBarOnClickListeners(@NonNull View view) {
-        final View title = findActionBarTitle(view);
-        final View subtitle = findActionBarSubTitle(view);
-        if (title != null) {
-            title.setOnClickListener(null);
-        }
-        if (subtitle != null) {
-            subtitle.setOnClickListener(null);
-        }
-    }
-
-    public static void setActionBarOnClickListener(@NonNull View view,
-                                                   @NonNull final View.OnClickListener onClickListener) {
-        final View title = findActionBarTitle(view);
-        final View subtitle = findActionBarSubTitle(view);
-        if (title != null) {
-            title.setOnClickListener(onClickListener);
-        }
-        if (subtitle != null) {
-            subtitle.setOnClickListener(onClickListener);
-        }
-    }
-
-    private static @Nullable View findActionBarTitle(@NonNull View root) {
-        return findActionBarItem(root, "action_bar_title", "mTitleTextView");
-    }
-
-    private static @Nullable
-    View findActionBarSubTitle(@NonNull View root) {
-        return findActionBarItem(root, "action_bar_subtitle", "mSubtitleTextView");
-    }
-
-    private static @Nullable View findActionBarItem(@NonNull View root,
-                                                    @NonNull String resourceName,
-                                                    @NonNull String toolbarFieldName) {
-        View result = findViewSupportOrAndroid(root, resourceName);
-
-        if (result == null) {
-            View actionBar = findViewSupportOrAndroid(root, "action_bar");
-            if (actionBar != null) {
-                result = reflectiveRead(actionBar, toolbarFieldName);
-            }
-        }
-        if (result == null && root.getClass().getName().endsWith("widget.Toolbar")) {
-            result = reflectiveRead(root, toolbarFieldName);
-        }
-        return result;
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    private static @Nullable View findViewSupportOrAndroid(@NonNull View root,
-                                                           @NonNull String resourceName) {
-        Context context = root.getContext();
-        View result = null;
-        if (result == null) {
-            int supportID = context.getResources().getIdentifier(resourceName, "id", context.getPackageName());
-            result = root.findViewById(supportID);
-        }
-        if (result == null) {
-            int androidID = context.getResources().getIdentifier(resourceName, "id", "android");
-            result = root.findViewById(androidID);
-        }
-        return result;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T> T reflectiveRead(@NonNull Object object, @NonNull String fieldName) {
-        try {
-            Field field = object.getClass().getDeclaredField(fieldName);
-            field.setAccessible(true);
-            return (T) field.get(object);
-        } catch (final Exception ex) {
-            return null;
-        }
-    }
-}

src/main/java/eu/siacs/conversations/ui/util/Attachment.java 🔗

@@ -38,6 +38,9 @@ import android.os.Parcelable;
 
 import com.google.common.base.MoreObjects;
 
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.utils.MimeUtils;
+
 import org.jetbrains.annotations.NotNull;
 
 import java.io.File;
@@ -46,9 +49,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
-import eu.siacs.conversations.utils.Compatibility;
-import eu.siacs.conversations.utils.MimeUtils;
-
 public class Attachment implements Parcelable {
 
     Attachment(Parcel in) {
@@ -71,17 +71,18 @@ public class Attachment implements Parcelable {
         return 0;
     }
 
-    public static final Creator<Attachment> CREATOR = new Creator<Attachment>() {
-        @Override
-        public Attachment createFromParcel(Parcel in) {
-            return new Attachment(in);
-        }
+    public static final Creator<Attachment> CREATOR =
+            new Creator<Attachment>() {
+                @Override
+                public Attachment createFromParcel(Parcel in) {
+                    return new Attachment(in);
+                }
 
-        @Override
-        public Attachment[] newArray(int size) {
-            return new Attachment[size];
-        }
-    };
+                @Override
+                public Attachment[] newArray(int size) {
+                    return new Attachment[size];
+                }
+            };
 
     public String getMime() {
         return mime;
@@ -103,7 +104,10 @@ public class Attachment implements Parcelable {
     }
 
     public enum Type {
-        FILE, IMAGE, LOCATION, RECORDING
+        FILE,
+        IMAGE,
+        LOCATION,
+        RECORDING
     }
 
     private final Uri uri;
@@ -125,8 +129,8 @@ public class Attachment implements Parcelable {
         this.uuid = UUID.randomUUID();
     }
 
-    public static boolean canBeSendInband(final List<Attachment> attachments) {
-        for (Attachment attachment : attachments) {
+    public static boolean canBeSendInBand(final List<Attachment> attachments) {
+        for (final Attachment attachment : attachments) {
             if (attachment.type != Type.LOCATION) {
                 return false;
             }
@@ -135,10 +139,30 @@ public class Attachment implements Parcelable {
     }
 
     public static List<Attachment> of(final Context context, Uri uri, Type type) {
-        final String mime = type == Type.LOCATION ? null : MimeUtils.guessMimeTypeFromUri(context, uri);
+        final String mime =
+                type == Type.LOCATION ? null : MimeUtils.guessMimeTypeFromUri(context, uri);
         return Collections.singletonList(new Attachment(uri, type, mime));
     }
 
+    public static Attachment of(final Message message) {
+        final UUID uuid = UUID.fromString(message.getUuid());
+        if (message.isGeoUri()) {
+            return new Attachment(uuid, Uri.EMPTY, Type.LOCATION, null);
+        }
+        final String mime = message.getMimeType();
+        if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) {
+            final Message.FileParams fileParams = message.getFileParams();
+            if (fileParams.width > 0 && fileParams.height > 0) {
+                return new Attachment(uuid, Uri.EMPTY, Type.FILE, "video/*");
+            } else if (fileParams.runtime > 0) {
+                return new Attachment(uuid, Uri.EMPTY, Type.FILE, "audio/*");
+            } else {
+                return new Attachment(uuid, Uri.EMPTY, Type.FILE, "application/octet-stream");
+            }
+        }
+        return new Attachment(uuid, Uri.EMPTY, Type.FILE, mime);
+    }
+
     public static List<Attachment> of(final Context context, List<Uri> uris, final String type) {
         final List<Attachment> attachments = new ArrayList<>();
         for (final Uri uri : uris) {
@@ -146,16 +170,25 @@ public class Attachment implements Parcelable {
                 continue;
             }
             final String mime = MimeUtils.guessMimeTypeFromUriAndMime(context, uri, type);
-            attachments.add(new Attachment(uri, mime != null && isImage(mime) ? Type.IMAGE : Type.FILE, mime));
+            attachments.add(
+                    new Attachment(
+                            uri, mime != null && isImage(mime) ? Type.IMAGE : Type.FILE, mime));
         }
         return attachments;
     }
 
     public static Attachment of(UUID uuid, final File file, String mime) {
-        return new Attachment(uuid, Uri.fromFile(file), mime != null && (isImage(mime) || mime.startsWith("video/")) ? Type.IMAGE : Type.FILE, mime);
+        return new Attachment(
+                uuid,
+                Uri.fromFile(file),
+                mime != null && (isImage(mime) || mime.startsWith("video/"))
+                        ? Type.IMAGE
+                        : Type.FILE,
+                mime);
     }
 
-    public static List<Attachment> extractAttachments(final Context context, final Intent intent, Type type) {
+    public static List<Attachment> extractAttachments(
+            final Context context, final Intent intent, Type type) {
         List<Attachment> uris = new ArrayList<>();
         if (intent == null) {
             return uris;
@@ -167,7 +200,8 @@ public class Attachment implements Parcelable {
             if (clipData != null) {
                 for (int i = 0; i < clipData.getItemCount(); ++i) {
                     final Uri uri = clipData.getItemAt(i).getUri();
-                    final String mime = MimeUtils.guessMimeTypeFromUriAndMime(context, uri, contentType);
+                    final String mime =
+                            MimeUtils.guessMimeTypeFromUriAndMime(context, uri, contentType);
                     uris.add(new Attachment(uri, type, mime));
                 }
             }
@@ -179,13 +213,12 @@ public class Attachment implements Parcelable {
     }
 
     public boolean renderThumbnail() {
-        return type == Type.IMAGE || (type == Type.FILE && mime != null && renderFileThumbnail(mime));
+        return type == Type.IMAGE
+                || (type == Type.FILE && mime != null && renderFileThumbnail(mime));
     }
 
     private static boolean renderFileThumbnail(final String mime) {
-        return mime.startsWith("video/")
-                || isImage(mime)
-                || "application/pdf".equals(mime);
+        return mime.startsWith("video/") || isImage(mime) || "application/pdf".equals(mime);
     }
 
     public Uri getUri() {

src/main/java/eu/siacs/conversations/ui/util/ConversationMenuConfigurator.java 🔗

@@ -102,14 +102,16 @@ public class ConversationMenuConfigurator {
 			return;
 		}
 
-		if (conversation.getNextEncryption() != Message.ENCRYPTION_NONE) {
-			menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
+		if (next == Message.ENCRYPTION_NONE) {
+			menuSecure.setIcon(R.drawable.ic_lock_open_outline_24dp);
+		} else {
+			menuSecure.setIcon(R.drawable.ic_lock_24dp);
 		}
 
 		pgp.setVisible(Config.supportOpenPgp());
 		none.setVisible(Config.supportUnencrypted() || conversation.getMode() == Conversation.MODE_MULTI);
 		axolotl.setVisible(Config.supportOmemo());
-		switch (conversation.getNextEncryption()) {
+		switch (next) {
 			case Message.ENCRYPTION_PGP:
 				menuSecure.setTitle(R.string.encrypted_with_openpgp);
 				pgp.setChecked(true);

src/main/java/eu/siacs/conversations/ui/util/MucDetailsContextMenuHelper.java 🔗

@@ -12,6 +12,8 @@ import android.view.View;
 
 import androidx.appcompat.app.AlertDialog;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
@@ -200,7 +202,7 @@ public final class MucDetailsContextMenuHelper {
                 activity.xmppConnectionService.changeRoleInConference(conversation, user.getName(), MucOptions.Role.NONE);
             }
         } else {
-            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
             builder.setTitle(R.string.ban_from_conference);
             String jid = user.getRealJid().asBareJid().toString();
             SpannableString message = new SpannableString(activity.getString(R.string.removing_from_public_conference, jid));

src/main/java/eu/siacs/conversations/ui/util/PresenceSelector.java 🔗

@@ -36,6 +36,8 @@ import android.widget.Toast;
 
 import androidx.appcompat.app.AlertDialog;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -72,7 +74,7 @@ public class PresenceSelector {
 
     private static void showPresenceSelectionDialog(final Activity activity, final Contact contact, final String[] resourceArray, final OnFullJidSelected onFullJidSelected) {
         final Presences presences = contact.getPresences();
-        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
         builder.setTitle(activity.getString(R.string.choose_presence));
         Pair<Map<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
         final Map<String, String> resourceTypeMap = typeAndName.first;
@@ -128,8 +130,8 @@ public class PresenceSelector {
         }
     }
 
-    public static void warnMutualPresenceSubscription(Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+    public static void warnMutualPresenceSubscription(final Activity activity, final Conversation conversation, final OnPresenceSelected listener) {
+        final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
         builder.setTitle(conversation.getContact().getJid().toString());
         builder.setMessage(R.string.without_mutual_presence_updates);
         builder.setNegativeButton(R.string.cancel, null);

src/main/java/eu/siacs/conversations/ui/util/SendButtonTool.java 🔗

@@ -31,8 +31,15 @@ package eu.siacs.conversations.ui.util;
 
 import android.app.Activity;
 import android.content.SharedPreferences;
-import android.content.res.TypedArray;
+import android.content.res.Configuration;
 import android.preference.PreferenceManager;
+import android.view.View;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.DrawableRes;
+import androidx.core.content.ContextCompat;
+
+import com.google.android.material.color.MaterialColors;
 
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Conversation;
@@ -42,149 +49,90 @@ import eu.siacs.conversations.utils.UIHelper;
 
 public class SendButtonTool {
 
-	public static SendButtonAction getAction(final Activity activity, final Conversation c, final String text) {
-		if (activity == null) {
-			return SendButtonAction.TEXT;
-		}
-		final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
-		final boolean empty = text.length() == 0;
-		final boolean conference = c.getMode() == Conversation.MODE_MULTI;
-		if (c.getCorrectingMessage() != null && (empty || text.equals(c.getCorrectingMessage().getBody()))) {
-			return SendButtonAction.CANCEL;
-		} else if (conference && !c.getAccount().httpUploadAvailable()) {
-			if (empty && c.getNextCounterpart() != null) {
-				return SendButtonAction.CANCEL;
-			} else {
-				return SendButtonAction.TEXT;
-			}
-		} else {
-			if (empty) {
-				if (conference && c.getNextCounterpart() != null) {
-					return SendButtonAction.CANCEL;
-				} else {
-					String setting = preferences.getString("quick_action", activity.getResources().getString(R.string.quick_action));
-					if (!"none".equals(setting) && UIHelper.receivedLocationQuestion(c.getLatestMessage())) {
-						return SendButtonAction.SEND_LOCATION;
-					} else {
-						if ("recent".equals(setting)) {
-							setting = preferences.getString(ConversationFragment.RECENTLY_USED_QUICK_ACTION, SendButtonAction.TEXT.toString());
-							return SendButtonAction.valueOfOrDefault(setting);
-						} else {
-							return SendButtonAction.valueOfOrDefault(setting);
-						}
-					}
-				}
-			} else {
-				return SendButtonAction.TEXT;
-			}
-		}
-	}
-
-	public static int getSendButtonImageResource(Activity activity, SendButtonAction action, Presence.Status status) {
-		switch (action) {
-			case TEXT:
-				switch (status) {
-					case CHAT:
-					case ONLINE:
-						return R.drawable.ic_send_text_online;
-					case AWAY:
-						return R.drawable.ic_send_text_away;
-					case XA:
-					case DND:
-						return R.drawable.ic_send_text_dnd;
-					default:
-						return getThemeResource(activity, R.attr.ic_send_text_offline, R.drawable.ic_send_text_offline);
-				}
-			case RECORD_VIDEO:
-				switch (status) {
-					case CHAT:
-					case ONLINE:
-						return R.drawable.ic_send_videocam_online;
-					case AWAY:
-						return R.drawable.ic_send_videocam_away;
-					case XA:
-					case DND:
-						return R.drawable.ic_send_videocam_dnd;
-					default:
-						return getThemeResource(activity, R.attr.ic_send_videocam_offline, R.drawable.ic_send_videocam_offline);
-				}
-			case TAKE_PHOTO:
-				switch (status) {
-					case CHAT:
-					case ONLINE:
-						return R.drawable.ic_send_photo_online;
-					case AWAY:
-						return R.drawable.ic_send_photo_away;
-					case XA:
-					case DND:
-						return R.drawable.ic_send_photo_dnd;
-					default:
-						return getThemeResource(activity, R.attr.ic_send_photo_offline, R.drawable.ic_send_photo_offline);
-				}
-			case RECORD_VOICE:
-				switch (status) {
-					case CHAT:
-					case ONLINE:
-						return R.drawable.ic_send_voice_online;
-					case AWAY:
-						return R.drawable.ic_send_voice_away;
-					case XA:
-					case DND:
-						return R.drawable.ic_send_voice_dnd;
-					default:
-						return getThemeResource(activity, R.attr.ic_send_voice_offline, R.drawable.ic_send_voice_offline);
-				}
-			case SEND_LOCATION:
-				switch (status) {
-					case CHAT:
-					case ONLINE:
-						return R.drawable.ic_send_location_online;
-					case AWAY:
-						return R.drawable.ic_send_location_away;
-					case XA:
-					case DND:
-						return R.drawable.ic_send_location_dnd;
-					default:
-						return getThemeResource(activity, R.attr.ic_send_location_offline, R.drawable.ic_send_location_offline);
-				}
-			case CANCEL:
-				switch (status) {
-					case CHAT:
-					case ONLINE:
-						return R.drawable.ic_send_cancel_online;
-					case AWAY:
-						return R.drawable.ic_send_cancel_away;
-					case XA:
-					case DND:
-						return R.drawable.ic_send_cancel_dnd;
-					default:
-						return getThemeResource(activity, R.attr.ic_send_cancel_offline, R.drawable.ic_send_cancel_offline);
-				}
-			case CHOOSE_PICTURE:
-				switch (status) {
-					case CHAT:
-					case ONLINE:
-						return R.drawable.ic_send_picture_online;
-					case AWAY:
-						return R.drawable.ic_send_picture_away;
-					case XA:
-					case DND:
-						return R.drawable.ic_send_picture_dnd;
-					default:
-						return getThemeResource(activity, R.attr.ic_send_picture_offline, R.drawable.ic_send_picture_offline);
-				}
-		}
-		return getThemeResource(activity, R.attr.ic_send_text_offline, R.drawable.ic_send_text_offline);
-	}
-
-	private static int getThemeResource(Activity activity, int r_attr_name, int r_drawable_def) {
-		int[] attrs = {r_attr_name};
-		TypedArray ta = activity.getTheme().obtainStyledAttributes(attrs);
-
-		int res = ta.getResourceId(0, r_drawable_def);
-		ta.recycle();
+    public static SendButtonAction getAction(
+            final Activity activity, final Conversation c, final String text) {
+        if (activity == null) {
+            return SendButtonAction.TEXT;
+        }
+        final SharedPreferences preferences =
+                PreferenceManager.getDefaultSharedPreferences(activity);
+        final boolean empty = text.isEmpty();
+        final boolean conference = c.getMode() == Conversation.MODE_MULTI;
+        if (c.getCorrectingMessage() != null
+                && (empty || text.equals(c.getCorrectingMessage().getBody()))) {
+            return SendButtonAction.CANCEL;
+        } else if (conference && !c.getAccount().httpUploadAvailable()) {
+            if (empty && c.getNextCounterpart() != null) {
+                return SendButtonAction.CANCEL;
+            } else {
+                return SendButtonAction.TEXT;
+            }
+        } else {
+            if (empty) {
+                if (conference && c.getNextCounterpart() != null) {
+                    return SendButtonAction.CANCEL;
+                } else {
+                    String setting =
+                            preferences.getString(
+                                    "quick_action",
+                                    activity.getResources().getString(R.string.quick_action));
+                    if (!"none".equals(setting)
+                            && UIHelper.receivedLocationQuestion(c.getLatestMessage())) {
+                        return SendButtonAction.SEND_LOCATION;
+                    } else {
+                        if ("recent".equals(setting)) {
+                            setting =
+                                    preferences.getString(
+                                            ConversationFragment.RECENTLY_USED_QUICK_ACTION,
+                                            SendButtonAction.TEXT.toString());
+                            return SendButtonAction.valueOfOrDefault(setting);
+                        } else {
+                            return SendButtonAction.valueOfOrDefault(setting);
+                        }
+                    }
+                }
+            } else {
+                return SendButtonAction.TEXT;
+            }
+        }
+    }
 
-		return res;
-	}
+    public @DrawableRes static int getSendButtonImageResource(final SendButtonAction action) {
+        return switch (action) {
+            case TEXT -> R.drawable.ic_send_24dp;
+            case TAKE_PHOTO -> R.drawable.ic_camera_alt_24dp;
+            case SEND_LOCATION -> R.drawable.ic_location_pin_24dp;
+            case CHOOSE_PICTURE -> R.drawable.ic_image_24dp;
+            case RECORD_VIDEO -> R.drawable.ic_videocam_24dp;
+            case RECORD_VOICE -> R.drawable.ic_mic_24dp;
+            case CANCEL -> R.drawable.ic_cancel_24dp;
+        };
+    }
 
+    public @ColorInt static int getSendButtonColor(final View view, final Presence.Status status) {
+        final boolean nightMode =
+                (view.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                        == Configuration.UI_MODE_NIGHT_YES;
+        return switch (status) {
+            case OFFLINE -> MaterialColors.getColor(
+                    view, com.google.android.material.R.attr.colorOnSurface);
+            case ONLINE, CHAT -> MaterialColors.harmonizeWithPrimary(
+                    view.getContext(),
+                    ContextCompat.getColor(
+                            view.getContext(), nightMode ? R.color.green_200 : R.color.green_800));
+            case AWAY -> MaterialColors.harmonizeWithPrimary(
+                    view.getContext(),
+                    ContextCompat.getColor(
+                            view.getContext(), nightMode ? R.color.amber_200 : R.color.amber_800));
+            case XA -> MaterialColors.harmonizeWithPrimary(
+                    view.getContext(),
+                    ContextCompat.getColor(
+                            view.getContext(),
+                            nightMode ? R.color.orange_200 : R.color.orange_800));
+            case DND -> MaterialColors.harmonizeWithPrimary(
+                    view.getContext(),
+                    ContextCompat.getColor(
+                            view.getContext(), nightMode ? R.color.red_200 : R.color.red_800));
+        };
+    }
 }

src/main/java/eu/siacs/conversations/ui/util/StyledAttributes.java 🔗

@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2018, Daniel Gultsch All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors
- * may be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package eu.siacs.conversations.ui.util;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-
-import androidx.annotation.AttrRes;
-import androidx.annotation.ColorInt;
-
-public class StyledAttributes {
-	public static android.graphics.drawable.Drawable getDrawable(Context context, @AttrRes int id) {
-		TypedArray typedArray = context.obtainStyledAttributes(new int[]{id});
-		android.graphics.drawable.Drawable drawable = typedArray.getDrawable(0);
-		typedArray.recycle();
-		return drawable;
-	}
-
-	public static float getFloat(Context context, @AttrRes int id) {
-		TypedArray typedArray = context.obtainStyledAttributes(new int[]{id});
-		float value = typedArray.getFloat(0,0f);
-		typedArray.recycle();
-		return value;
-	}
-
-	public static @ColorInt int getColor(Context context, @AttrRes int attr) {
-		TypedArray typedArray = context.obtainStyledAttributes(new int[]{attr});
-		int color = typedArray.getColor(0,0);
-		typedArray.recycle();
-		return color;
-	}
-}

src/main/java/eu/siacs/conversations/ui/util/ToolbarUtils.java 🔗

@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package eu.siacs.conversations.ui.util;
+
+import static java.util.Collections.max;
+import static java.util.Collections.min;
+
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.ActionMenuView;
+import androidx.appcompat.widget.Toolbar;
+
+import com.google.android.material.appbar.MaterialToolbar;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+public class ToolbarUtils {
+
+    private static final Comparator<View> VIEW_TOP_COMPARATOR =
+            new Comparator<View>() {
+                @Override
+                public int compare(View view1, View view2) {
+                    return view1.getTop() - view2.getTop();
+                }
+            };
+
+    private ToolbarUtils() {
+        // Private constructor to prevent unwanted construction.
+    }
+
+    public static void resetActionBarOnClickListeners(@NonNull MaterialToolbar view) {
+        final TextView title = getTitleTextView(view);
+        final TextView subtitle = getSubtitleTextView(view);
+        if (title != null) {
+            title.setOnClickListener(null);
+        }
+        if (subtitle != null) {
+            subtitle.setOnClickListener(null);
+        }
+    }
+
+    public static void setActionBarOnClickListener(
+            @NonNull MaterialToolbar view, @NonNull final View.OnClickListener onClickListener) {
+        final TextView title = getTitleTextView(view);
+        final TextView subtitle = getSubtitleTextView(view);
+        if (title != null) {
+            title.setOnClickListener(onClickListener);
+        }
+        if (subtitle != null) {
+            subtitle.setOnClickListener(onClickListener);
+        }
+    }
+
+    @Nullable
+    public static TextView getTitleTextView(@NonNull Toolbar toolbar) {
+        List<TextView> textViews = getTextViewsWithText(toolbar, toolbar.getTitle());
+        return textViews.isEmpty() ? null : min(textViews, VIEW_TOP_COMPARATOR);
+    }
+
+    @Nullable
+    public static TextView getSubtitleTextView(@NonNull Toolbar toolbar) {
+        List<TextView> textViews = getTextViewsWithText(toolbar, toolbar.getSubtitle());
+        return textViews.isEmpty() ? null : max(textViews, VIEW_TOP_COMPARATOR);
+    }
+
+    private static List<TextView> getTextViewsWithText(
+            @NonNull Toolbar toolbar, CharSequence text) {
+        List<TextView> textViews = new ArrayList<>();
+        for (int i = 0; i < toolbar.getChildCount(); i++) {
+            View child = toolbar.getChildAt(i);
+            if (child instanceof TextView textView) {
+                if (TextUtils.equals(textView.getText(), text)) {
+                    textViews.add(textView);
+                }
+            }
+        }
+        return textViews;
+    }
+
+    @Nullable
+    public static ImageView getLogoImageView(@NonNull Toolbar toolbar) {
+        return getImageView(toolbar, toolbar.getLogo());
+    }
+
+    @Nullable
+    private static ImageView getImageView(@NonNull Toolbar toolbar, @Nullable Drawable content) {
+        if (content == null) {
+            return null;
+        }
+        for (int i = 0; i < toolbar.getChildCount(); i++) {
+            View child = toolbar.getChildAt(i);
+            if (child instanceof ImageView imageView) {
+                Drawable drawable = imageView.getDrawable();
+                if (drawable != null
+                        && drawable.getConstantState() != null
+                        && drawable.getConstantState().equals(content.getConstantState())) {
+                    return imageView;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    public static View getSecondaryActionMenuItemView(@NonNull Toolbar toolbar) {
+        ActionMenuView actionMenuView = getActionMenuView(toolbar);
+        if (actionMenuView != null) {
+            // Only return the first child of the ActionMenuView if there is more than one child
+            if (actionMenuView.getChildCount() > 1) {
+                return actionMenuView.getChildAt(0);
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    public static ActionMenuView getActionMenuView(@NonNull Toolbar toolbar) {
+        for (int i = 0; i < toolbar.getChildCount(); i++) {
+            View child = toolbar.getChildAt(i);
+            if (child instanceof ActionMenuView) {
+                return (ActionMenuView) child;
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    public static ImageButton getNavigationIconButton(@NonNull Toolbar toolbar) {
+        Drawable navigationIcon = toolbar.getNavigationIcon();
+        if (navigationIcon == null) {
+            return null;
+        }
+        for (int i = 0; i < toolbar.getChildCount(); i++) {
+            View child = toolbar.getChildAt(i);
+            if (child instanceof ImageButton imageButton) {
+                if (imageButton.getDrawable() == navigationIcon) {
+                    return imageButton;
+                }
+            }
+        }
+        return null;
+    }
+}

src/main/java/eu/siacs/conversations/ui/widget/ImmediateAutoCompleteTextView.java 🔗

@@ -32,7 +32,9 @@ package eu.siacs.conversations.ui.widget;
 import android.content.Context;
 import android.util.AttributeSet;
 
-public class ImmediateAutoCompleteTextView extends androidx.appcompat.widget.AppCompatAutoCompleteTextView {
+import com.google.android.material.textfield.MaterialAutoCompleteTextView;
+
+public class ImmediateAutoCompleteTextView extends MaterialAutoCompleteTextView {
 
 	public ImmediateAutoCompleteTextView(Context context, AttributeSet attrs) {
 		super(context, attrs);

src/main/java/eu/siacs/conversations/ui/widget/ScannerView.java 🔗

@@ -29,6 +29,8 @@ import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.view.View;
 
+import androidx.core.content.ContextCompat;
+
 import com.google.zxing.ResultPoint;
 
 import java.util.HashMap;
@@ -58,25 +60,24 @@ public class ScannerView extends View {
 
     public ScannerView(final Context context, final AttributeSet attrs) {
         super(context, attrs);
-
-        final Resources res = getResources();
-        maskColor = res.getColor(R.color.black54);
-        maskResultColor = res.getColor(R.color.black87);
-        laserColor = res.getColor(R.color.red500);
-        dotColor = res.getColor(R.color.orange500);
-        dotResultColor = res.getColor(R.color.scan_result_dots);
+        final Resources resources = context.getResources();
+        maskColor = ContextCompat.getColor(context, R.color.black54);
+        maskResultColor = ContextCompat.getColor(context, R.color.black87);
+        laserColor = ContextCompat.getColor(context, R.color.red_500);
+        dotColor = ContextCompat.getColor(context, R.color.orange_500);
+        dotResultColor = ContextCompat.getColor(context, R.color.green_500);
 
         maskPaint = new Paint();
         maskPaint.setStyle(Style.FILL);
 
         laserPaint = new Paint();
-        laserPaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.scan_laser_width));
+        laserPaint.setStrokeWidth(resources.getDimensionPixelSize(R.dimen.scan_laser_width));
         laserPaint.setStyle(Style.STROKE);
 
         dotPaint = new Paint();
         dotPaint.setAlpha(DOT_OPACITY);
         dotPaint.setStyle(Style.STROKE);
-        dotPaint.setStrokeWidth(res.getDimension(R.dimen.scan_dot_size));
+        dotPaint.setStrokeWidth(resources.getDimension(R.dimen.scan_dot_size));
         dotPaint.setAntiAlias(true);
     }
 

src/main/java/eu/siacs/conversations/ui/widget/SwipeRefreshListFragment.java 🔗

@@ -26,8 +26,6 @@ import android.widget.ListView;
 import androidx.fragment.app.ListFragment;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
-import eu.siacs.conversations.ui.util.StyledAttributes;
-
 /**
  * Subclass of {@link androidx.fragment.app.ListFragment} which provides automatic support for
  * providing the 'swipe-to-refresh' UX gesture by wrapping the the content view in a
@@ -56,7 +54,8 @@ public class SwipeRefreshListFragment extends ListFragment {
 
         final Context context = getActivity();
         if (context != null) {
-            mSwipeRefreshLayout.setColorSchemeColors(StyledAttributes.getColor(context, androidx.appcompat.R.attr.colorAccent));
+            // TODO are default colors fine here?
+            //mSwipeRefreshLayout.setColorSchemeColors(StyledAttributes.getColor(context, androidx.appcompat.R.attr.colorAccent));
         }
 
         if (onRefreshListener != null) {

src/main/java/eu/siacs/conversations/ui/widget/UnreadCountCustomView.java 🔗

@@ -9,6 +9,7 @@ import android.graphics.Typeface;
 import android.util.AttributeSet;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.core.content.ContextCompat;
 
 import eu.siacs.conversations.R;
@@ -18,6 +19,7 @@ public class UnreadCountCustomView extends View {
     private int unreadCount;
     private Paint paint, textPaint;
     private int backgroundColor = 0xff326130;
+    private int textColor = Color.WHITE;
 
     public UnreadCountCustomView(Context context) {
         super(context);
@@ -38,7 +40,8 @@ public class UnreadCountCustomView extends View {
 
     private void initXMLAttrs(Context context, AttributeSet attrs) {
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UnreadCountCustomView);
-        setBackgroundColor(a.getColor(a.getIndex(0), ContextCompat.getColor(context, R.color.green700_desaturated)));
+        setBackgroundColor(a.getColor(a.getIndex(0), ContextCompat.getColor(context, R.color.md_theme_light_tertiaryContainer)));
+        this.textColor = a.getColor(a.getIndex(1),ContextCompat.getColor(context, R.color.md_theme_light_onTertiaryContainer));
         a.recycle();
     }
 
@@ -47,14 +50,14 @@ public class UnreadCountCustomView extends View {
         paint.setColor(backgroundColor);
         paint.setAntiAlias(true);
         textPaint = new Paint();
-        textPaint.setColor(Color.WHITE);
+        textPaint.setColor(textColor);
         textPaint.setTextAlign(Paint.Align.CENTER);
         textPaint.setAntiAlias(true);
         textPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    protected void onDraw(@NonNull Canvas canvas) {
         super.onDraw(canvas);
         float midx = canvas.getWidth() / 2.0f;
         float midy = canvas.getHeight() / 2.0f;

src/main/java/eu/siacs/conversations/utils/AccountUtils.java 🔗

@@ -61,11 +61,7 @@ public class AccountUtils {
         final ArrayList<String> accounts = new ArrayList<>();
         for (final Account account : service.getAccounts()) {
             if (account.isEnabled()) {
-                if (Config.DOMAIN_LOCK != null) {
-                    accounts.add(account.getJid().getEscapedLocal());
-                } else {
-                    accounts.add(account.getJid().asBareJid().toEscapedString());
-                }
+                accounts.add(account.getJid().asBareJid().toEscapedString());
             }
         }
         return accounts;

src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java 🔗

@@ -10,6 +10,8 @@ import android.util.Log;
 
 import androidx.appcompat.app.AlertDialog;
 
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+
 import java.io.BufferedReader;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -72,8 +74,7 @@ public class ExceptionHelper {
                     report.append("SHA-1: ").append(CryptoHelper.getFingerprintCert(packageInfo.signatures[0].toByteArray())).append('\n');
                 }
                 report.append('\n');
-            } catch (Exception e) {
-                e.printStackTrace();
+            } catch (final Exception e) {
                 return false;
             }
             String line;
@@ -83,7 +84,7 @@ public class ExceptionHelper {
             }
             file.close();
             activity.deleteFile(FILENAME);
-            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+            final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);
             builder.setTitle(activity.getString(R.string.crash_report_title, activity.getString(R.string.app_name)));
             builder.setMessage(activity.getString(R.string.crash_report_message, activity.getString(R.string.app_name)));
             builder.setPositiveButton(activity.getText(R.string.send_now), (dialog, which) -> {

src/main/java/eu/siacs/conversations/utils/IrregularUnicodeDetector.java 🔗

@@ -40,6 +40,8 @@ import android.util.LruCache;
 
 import androidx.annotation.ColorInt;
 
+import com.google.android.material.color.MaterialColors;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -53,7 +55,6 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import eu.siacs.conversations.R;
-import eu.siacs.conversations.ui.util.StyledAttributes;
 import eu.siacs.conversations.xmpp.Jid;
 
 public class IrregularUnicodeDetector {
@@ -76,8 +77,8 @@ public class IrregularUnicodeDetector {
 		}
 	}
 
-	public static Spannable style(Context context, Jid jid) {
-		return style(jid, StyledAttributes.getColor(context, R.attr.color_warning));
+	public static Spannable style(final Context context, Jid jid) {
+		return style(jid, MaterialColors.getColor(context, com.google.android.material.R.attr.colorError,"colorError not found"));
 	}
 
 	private static Spannable style(Jid jid, @ColorInt int color) {

src/main/java/eu/siacs/conversations/utils/MimeUtils.java 🔗

@@ -328,6 +328,8 @@ public final class MimeUtils {
         add("image/x-xbitmap", "xbm");
         add("image/x-xpixmap", "xpm");
         add("image/x-xwindowdump", "xwd");
+        add("message/rfc822","eml");
+        add("message/rfc822","mime");
         add("model/iges", "igs");
         add("model/iges", "iges");
         add("model/mesh", "msh");

src/main/java/eu/siacs/conversations/utils/StylingHelper.java 🔗

@@ -49,6 +49,8 @@ import android.widget.TextView;
 import androidx.annotation.ColorInt;
 import androidx.core.content.ContextCompat;
 
+import com.google.android.material.color.MaterialColors;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -94,10 +96,10 @@ public class StylingHelper {
 		format(editable, end, editable.length() - 1, textColor);
 	}
 
-	public static void highlight(final Context context, final Editable editable, List<String> needles, boolean dark) {
-		for (String needle : needles) {
+	public static void highlight(final TextView view, final Editable editable, final List<String> needles) {
+		for (final String needle : needles) {
 			if (!FtsUtils.isKeyword(needle)) {
-				highlight(context, editable, needle, dark);
+				highlight(view, editable, needle);
 			}
 		}
 	}
@@ -124,14 +126,14 @@ public class StylingHelper {
 		return words;
 	}
 
-	private static void highlight(final Context context, final Editable editable, String needle, boolean dark) {
+	private static void highlight(final TextView view, final Editable editable, final String needle) {
 		final int length = needle.length();
 		String string = editable.toString();
 		int start = indexOfIgnoreCase(string, needle, 0);
 		while (start != -1) {
 			int end = start + length;
-			editable.setSpan(new BackgroundColorSpan(ContextCompat.getColor(context, dark ? R.color.blue_a100 : R.color.blue_a400)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
-			editable.setSpan(new ForegroundColorSpan(ContextCompat.getColor(context, dark ? R.color.black87 : R.color.white)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
+			editable.setSpan(new BackgroundColorSpan(MaterialColors.getColor(view, com.google.android.material.R.attr.colorPrimaryFixedDim)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
+			editable.setSpan(new ForegroundColorSpan(MaterialColors.getColor(view, com.google.android.material.R.attr.colorOnPrimaryFixed)), start, end, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
 			start = indexOfIgnoreCase(string, needle, start + length);
 		}
 
@@ -141,8 +143,7 @@ public class StylingHelper {
 		if (start == 0 && charSequence.length() + 1 == end) {
 			return charSequence;
 		}
-		if (charSequence instanceof Spannable) {
-			Spannable spannable = (Spannable) charSequence;
+		if (charSequence instanceof Spannable spannable) {
 			Spannable sub = (Spannable) spannable.subSequence(start, end);
 			for (Class<? extends ParcelableSpan> clazz : SPAN_CLASSES) {
 				ParcelableSpan[] spannables = spannable.getSpans(start, end, clazz);
@@ -175,25 +176,14 @@ public class StylingHelper {
 		}
 	}
 
-	public static boolean isDarkText(TextView textView) {
-		int argb = textView.getCurrentTextColor();
-		return Color.red(argb) + Color.green(argb) + Color.blue(argb) == 0;
-	}
-
-	private static ParcelableSpan createSpanForStyle(ImStyleParser.Style style) {
-		switch (style.getKeyword()) {
-			case "*":
-				return new StyleSpan(Typeface.BOLD);
-			case "_":
-				return new StyleSpan(Typeface.ITALIC);
-			case "~":
-				return new StrikethroughSpan();
-			case "`":
-			case "```":
-				return new TypefaceSpan("monospace");
-			default:
-				throw new AssertionError("Unknown Style");
-		}
+	private static ParcelableSpan createSpanForStyle(final ImStyleParser.Style style) {
+        return switch (style.getKeyword()) {
+            case "*" -> new StyleSpan(Typeface.BOLD);
+            case "_" -> new StyleSpan(Typeface.ITALIC);
+            case "~" -> new StrikethroughSpan();
+            case "`", "```" -> new TypefaceSpan("monospace");
+            default -> throw new AssertionError("Unknown Style");
+        };
 	}
 
 	private static void makeKeywordOpaque(final Editable editable, int start, int end, @ColorInt int fallbackTextColor) {

src/main/java/eu/siacs/conversations/utils/ThemeHelper.java 🔗

@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2018, Daniel Gultsch All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation and/or
- * other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its contributors
- * may be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package eu.siacs.conversations.utils;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.preference.PreferenceManager;
-import android.util.TypedValue;
-import android.widget.TextView;
-
-import androidx.annotation.StyleRes;
-import androidx.core.content.ContextCompat;
-
-import com.google.android.material.snackbar.Snackbar;
-
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.ui.SettingsActivity;
-
-public class ThemeHelper {
-
-	public static int find(final Context context) {
-		final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
-		final Resources resources = context.getResources();
-		final boolean dark = isDark(sharedPreferences, resources);
-		final String fontSize = sharedPreferences.getString("font_size", resources.getString(R.string.default_font_size));
-		switch (fontSize) {
-			case "medium":
-				return dark ? R.style.ConversationsTheme_Dark_Medium : R.style.ConversationsTheme_Medium;
-			case "large":
-				return dark ? R.style.ConversationsTheme_Dark_Large : R.style.ConversationsTheme_Large;
-			default:
-				return dark ? R.style.ConversationsTheme_Dark : R.style.ConversationsTheme;
-		}
-	}
-
-	public static int findDialog(Context context) {
-		final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
-		final Resources resources = context.getResources();
-		final boolean dark = isDark(sharedPreferences, resources);
-		final String fontSize = sharedPreferences.getString("font_size", resources.getString(R.string.default_font_size));
-		switch (fontSize) {
-			case "medium":
-				return dark ? R.style.ConversationsTheme_Dark_Dialog_Medium : R.style.ConversationsTheme_Dialog_Medium;
-			case "large":
-				return dark ? R.style.ConversationsTheme_Dark_Dialog_Large : R.style.ConversationsTheme_Dialog_Large;
-			default:
-				return dark ? R.style.ConversationsTheme_Dark_Dialog : R.style.ConversationsTheme_Dialog;
-		}
-	}
-
-	private static boolean isDark(final SharedPreferences sharedPreferences, final Resources resources) {
-		final String setting = sharedPreferences.getString(SettingsActivity.THEME, resources.getString(R.string.theme));
-		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && "automatic".equals(setting)) {
-			return (resources.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
-		} else {
-			return "dark".equals(setting);
-		}
-	}
-
-	public static boolean isDark(@StyleRes int id) {
-		switch (id) {
-			case R.style.ConversationsTheme_Dark:
-			case R.style.ConversationsTheme_Dark_Large:
-			case R.style.ConversationsTheme_Dark_Medium:
-				return true;
-			default:
-				return false;
-		}
-	}
-
-	public static void fix(Snackbar snackbar) {
-		final Context context = snackbar.getContext();
-		TypedArray typedArray = context.obtainStyledAttributes(new int[]{R.attr.TextSizeBody1});
-		final float size = typedArray.getDimension(0,0f);
-		typedArray.recycle();
-		if (size != 0f) {
-			final TextView text = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
-			final TextView action = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_action);
-			if (text != null && action != null) {
-				text.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
-				action.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
-				action.setTextColor(ContextCompat.getColor(context, R.color.blue_a100));
-			}
-		}
-	}
-}