Procházet zdrojové kódy

Version 6.1.2-1086

Threema před 2 měsíci
rodič
revize
78daf05ac6
88 změnil soubory, kde provedl 635 přidání a 264 odebrání
  1. 1 0
      .gitignore
  2. 33 26
      app/build.gradle.kts
  3. 2 2
      app/src/green/java/ch/threema/app/compose/theme/color/BrandColor.kt
  4. 2 2
      app/src/hms/java/ch/threema/app/compose/theme/color/BrandColor.kt
  5. 2 2
      app/src/libre/java/ch/threema/app/compose/theme/color/BrandColor.kt
  6. 2 3
      app/src/libre/play/release-notes/de/default.txt
  7. 2 3
      app/src/libre/play/release-notes/en-US/default.txt
  8. 66 9
      app/src/main/java/ch/threema/app/activities/EnterSerialActivity.java
  9. 0 1
      app/src/main/java/ch/threema/app/activities/ThreemaActivity.java
  10. 6 1
      app/src/main/java/ch/threema/app/activities/WorkIntroActivity.kt
  11. 20 3
      app/src/main/java/ch/threema/app/backuprestore/csv/BackupService.java
  12. 37 50
      app/src/main/java/ch/threema/app/compose/common/buttons/ButtonPrimary.kt
  13. 5 5
      app/src/main/java/ch/threema/app/compose/theme/color/ColorsLight.kt
  14. 37 3
      app/src/main/java/ch/threema/app/home/HomeActivity.java
  15. 0 7
      app/src/main/java/ch/threema/app/multidevice/wizard/steps/LinkNewDeviceEmojiSelectionView.kt
  16. 8 10
      app/src/main/java/ch/threema/app/preference/SettingsAdvancedOptionsFragment.java
  17. 3 3
      app/src/main/java/ch/threema/app/restrictions/ApplyAppRestrictionsWorker.kt
  18. 1 0
      app/src/main/java/ch/threema/app/services/UserServiceImpl.java
  19. 47 22
      app/src/main/java/ch/threema/app/utils/AndroidContactUtil.java
  20. 4 0
      app/src/main/java/ch/threema/app/utils/ConfigUtils.java
  21. 10 2
      app/src/main/java/ch/threema/app/voip/activities/CallActivity.java
  22. 1 1
      app/src/main/res/color-night-v21/bubble_receive_colorstatelist.xml
  23. 1 1
      app/src/main/res/color-night-v21/bubble_send_colorstatelist.xml
  24. 1 1
      app/src/main/res/color-night-v21/bubble_status_colorstatelist.xml
  25. 0 7
      app/src/main/res/color-night-v22/bubble_send_text_colorstatelist.xml
  26. 2 2
      app/src/main/res/color-night-v23/bubble_receive_colorstatelist.xml
  27. 2 2
      app/src/main/res/color-night-v23/bubble_send_colorstatelist.xml
  28. 7 0
      app/src/main/res/color-night-v23/bubble_send_text_colorstatelist.xml
  29. 7 0
      app/src/main/res/color-night-v23/bubble_status_colorstatelist.xml
  30. 2 2
      app/src/main/res/color-v21/bubble_receive_colorstatelist.xml
  31. 2 2
      app/src/main/res/color-v21/bubble_send_colorstatelist.xml
  32. 2 2
      app/src/main/res/color-v21/bubble_status_colorstatelist.xml
  33. 1 1
      app/src/main/res/color-v23/bubble_receive_colorstatelist.xml
  34. 1 1
      app/src/main/res/color-v23/bubble_send_colorstatelist.xml
  35. 1 1
      app/src/main/res/color-v23/bubble_status_colorstatelist.xml
  36. 2 2
      app/src/main/res/color/bubble_receive_colorstatelist.xml
  37. 1 1
      app/src/main/res/color/bubble_receive_text_colorstatelist.xml
  38. 2 2
      app/src/main/res/color/bubble_send_colorstatelist.xml
  39. 2 2
      app/src/main/res/color/bubble_send_text_colorstatelist.xml
  40. 2 2
      app/src/main/res/color/bubble_status_colorstatelist.xml
  41. 1 1
      app/src/main/res/color/bubble_sticker_colorstatelist.xml
  42. 2 1
      app/src/main/res/color/bubble_text_link_colorstatelist.xml
  43. 1 0
      app/src/main/res/color/bubble_text_quote_colorstatelist.xml
  44. 1 0
      app/src/main/res/color/bubble_text_status_colorstatelist.xml
  45. 2 2
      app/src/main/res/color/emojireactions_background_colorstatelist.xml
  46. 1 1
      app/src/main/res/drawable-night/bubble_fade_recv_selector.xml
  47. 18 0
      app/src/main/res/drawable-night/bubble_fade_send_selector.xml
  48. 1 1
      app/src/main/res/drawable/bubble_fade_recv_selector.xml
  49. 1 1
      app/src/main/res/drawable/bubble_fade_send_selector.xml
  50. 0 22
      app/src/main/res/drawable/ic_app_icon_consumer.xml
  51. 31 0
      app/src/main/res/drawable/ic_app_icon_private.xml
  52. 1 0
      app/src/main/res/layout/activity_permission_request.xml
  53. 1 0
      app/src/main/res/layout/activity_server_message.xml
  54. 0 1
      app/src/main/res/layout/activity_sessions_intro.xml
  55. 1 1
      app/src/main/res/layout/fragment_link_new_device_verify.xml
  56. 2 1
      app/src/main/res/layout/view_emoji_selection.xml
  57. 1 1
      app/src/main/res/layout/work_intro_consumer_notice.xml
  58. 69 1
      app/src/main/res/values-be-rBY/strings.xml
  59. 36 3
      app/src/main/res/values-bg/strings.xml
  60. 3 0
      app/src/main/res/values-ca/strings.xml
  61. 6 1
      app/src/main/res/values-cs/strings.xml
  62. 8 1
      app/src/main/res/values-de/strings.xml
  63. 6 1
      app/src/main/res/values-es/strings.xml
  64. 6 1
      app/src/main/res/values-fr/strings.xml
  65. 6 1
      app/src/main/res/values-gsw/strings.xml
  66. 3 0
      app/src/main/res/values-hu/strings.xml
  67. 6 1
      app/src/main/res/values-it/strings.xml
  68. 3 0
      app/src/main/res/values-ja/strings.xml
  69. 6 1
      app/src/main/res/values-nl-rNL/strings.xml
  70. 3 0
      app/src/main/res/values-no/strings.xml
  71. 6 1
      app/src/main/res/values-pl/strings.xml
  72. 6 1
      app/src/main/res/values-pt-rBR/strings.xml
  73. 8 3
      app/src/main/res/values-ru/strings.xml
  74. 3 1
      app/src/main/res/values-sk/strings.xml
  75. 6 1
      app/src/main/res/values-tr/strings.xml
  76. 8 3
      app/src/main/res/values-uk/strings.xml
  77. 6 1
      app/src/main/res/values-zh-rCN/strings.xml
  78. 6 1
      app/src/main/res/values-zh-rTW/strings.xml
  79. 2 2
      app/src/main/res/values/colors.xml
  80. 6 6
      app/src/main/res/values/colors_theme.xml
  81. 6 1
      app/src/main/res/values/strings.xml
  82. 8 4
      app/src/main/res/values/styles.xml
  83. 2 1
      app/src/main/res/values/untranslatable_strings.xml
  84. 2 2
      app/src/none/java/ch/threema/app/compose/theme/color/BrandColor.kt
  85. 2 2
      app/src/onprem/res/drawable/ic_notification_small.xml
  86. 2 2
      app/src/store_google/java/ch/threema/app/compose/theme/color/BrandColor.kt
  87. 2 2
      app/src/store_threema/java/ch/threema/app/compose/theme/color/BrandColor.kt
  88. 1 0
      domain/src/main/java/ch/threema/domain/protocol/connection/layer/MonitoringLayer.kt

+ 1 - 0
.gitignore

@@ -17,6 +17,7 @@ fastlane/jenkins-screenshots/
 export/
 threema-android-*
 release/
+reproduce/
 .cxx/
 **/.DS_Store
 .kotlin

+ 33 - 26
app/build.gradle.kts

@@ -47,7 +47,7 @@ if (gradle.startParameter.taskRequests.toString().contains("Hms")) {
 /**
  * Only use the scheme "<major>.<minor>.<patch>" for the appVersion
  */
-val appVersion = "6.1.1"
+val appVersion = "6.1.2"
 
 /**
  * betaSuffix with leading dash (e.g. `-beta1`).
@@ -56,7 +56,7 @@ val appVersion = "6.1.1"
  */
 val betaSuffix = ""
 
-val defaultVersionCode = 1084
+val defaultVersionCode = 1086
 
 /**
  * Map with keystore paths (if found).
@@ -87,7 +87,7 @@ android {
         targetSdk = 34
         vectorDrawables.useSupportLibrary = true
         applicationId = "ch.threema.app"
-        testApplicationId = "ch.threema.app.test"
+        testApplicationId = "$applicationId.test"
         versionCode = defaultVersionCode
         versionName = "$appVersion$betaSuffix"
 
@@ -96,8 +96,8 @@ android {
         )
         // package name used for sync adapter - needs to match mime types below
         stringResValue("package_name", applicationId!!)
-        stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.profile")
-        stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.call")
+        stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
+        stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
 
         intBuildConfigField("MAX_GROUP_SIZE", 256)
         stringBuildConfigField("CHAT_SERVER_PREFIX", "g-")
@@ -153,15 +153,18 @@ android {
         stringBuildConfigField("contactActionUrl", "threema.id")
         stringBuildConfigField("groupLinkActionUrl", "threema.group")
 
+        // The OPPF url must be null in the default config. Do not change this.
+        stringBuildConfigField("PRESET_OPPF_URL", null)
+
         with(manifestPlaceholders) {
             put("uriScheme", "threema")
             put("contactActionUrl", "threema.id")
             put("groupLinkActionUrl", "threema.group")
             put("actionUrl", "go.threema.ch")
-            put("callMimeType", "vnd.android.cursor.item/vnd.ch.threema.app.call")
+            put("callMimeType", "vnd.android.cursor.item/vnd.$applicationId.call")
         }
 
-        testInstrumentationRunner = "ch.threema.app.ThreemaTestRunner"
+        testInstrumentationRunner = "$applicationId.ThreemaTestRunner"
 
         // Only include language resources for those languages
         androidResources.localeFilters.addAll(
@@ -233,11 +236,11 @@ android {
         create("store_google_work") {
             versionName = "${appVersion}k$betaSuffix"
             applicationId = "ch.threema.app.work"
-            testApplicationId = "ch.threema.app.work.test"
+            testApplicationId = "$applicationId.test"
             setProductNames(appName = "Threema Work")
             stringResValue("package_name", applicationId!!)
-            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile")
-            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call")
+            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
+            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
             stringBuildConfigField("CHAT_SERVER_PREFIX", "w-")
             stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "ds.w-")
             stringBuildConfigField("MEDIA_PATH", "ThreemaWork")
@@ -254,16 +257,16 @@ android {
             with(manifestPlaceholders) {
                 put("uriScheme", "threemawork")
                 put("actionUrl", "work.threema.ch")
-                put("callMimeType", "vnd.android.cursor.item/vnd.ch.threema.app.work.call")
+                put("callMimeType", "vnd.android.cursor.item/vnd.$applicationId.call")
             }
         }
         create("green") {
             applicationId = "ch.threema.app.green"
-            testApplicationId = "ch.threema.app.green.test"
+            testApplicationId = "$applicationId.test"
             setProductNames(appName = "Threema Green")
             stringResValue("package_name", applicationId!!)
-            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.green.profile")
-            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.green.call")
+            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
+            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
             stringBuildConfigField("MEDIA_PATH", "ThreemaGreen")
             stringBuildConfigField("CHAT_SERVER_SUFFIX", ".0.test.threema.ch")
             // This public key is pinned for the chat server protocol.
@@ -282,14 +285,14 @@ android {
         create("sandbox_work") {
             versionName = "${appVersion}k$betaSuffix"
             applicationId = "ch.threema.app.sandbox.work"
-            testApplicationId = "ch.threema.app.sandbox.work.test"
+            testApplicationId = "$applicationId.test"
             setProductNames(
                 appName = "Threema Sandbox Work",
                 appNameDesktop = "Threema Blue",
             )
             stringResValue("package_name", applicationId!!)
-            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.work.profile")
-            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.work.call")
+            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
+            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
             stringBuildConfigField("CHAT_SERVER_PREFIX", "w-")
             stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "ds.w-")
             stringBuildConfigField("CHAT_SERVER_SUFFIX", ".0.test.threema.ch")
@@ -325,15 +328,15 @@ android {
         create("onprem") {
             versionName = "${appVersion}o$betaSuffix"
             applicationId = "ch.threema.app.onprem"
-            testApplicationId = "ch.threema.app.onprem.test"
+            testApplicationId = "$applicationId.test"
             setProductNames(
                 appName = "Threema OnPrem",
                 shortAppName = "Threema",
                 companyName = "Threema",
             )
             stringResValue("package_name", applicationId!!)
-            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.onprem.profile")
-            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.onprem.call")
+            stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
+            stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
             intBuildConfigField("MAX_GROUP_SIZE", 256)
             stringBuildConfigField("CHAT_SERVER_PREFIX", "")
             stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "")
@@ -353,15 +356,19 @@ android {
             stringBuildConfigField("LOG_TAG", "3maop")
 
             // config fields for action URLs / deep links
-            stringBuildConfigField("uriScheme", "threemaonprem")
-            stringBuildConfigField("actionUrl", "onprem.threema.ch")
+            val uriScheme = "threemaonprem"
+            val actionUrl = "onprem.threema.ch"
+            stringBuildConfigField("uriScheme", uriScheme)
+            stringBuildConfigField("actionUrl", actionUrl)
+
+            stringBuildConfigField("PRESET_OPPF_URL", null)
 
             stringBuildConfigField("MD_CLIENT_DOWNLOAD_URL", "https://three.ma/mdo")
 
             with(manifestPlaceholders) {
-                put("uriScheme", "threemaonprem")
-                put("actionUrl", "onprem.threema.ch")
-                put("callMimeType", "vnd.android.cursor.item/vnd.ch.threema.app.onprem.call")
+                put("uriScheme", uriScheme)
+                put("actionUrl", actionUrl)
+                put("callMimeType", "vnd.android.cursor.item/vnd.$applicationId.call")
             }
         }
         create("blue") {
@@ -438,7 +445,7 @@ android {
         create("libre") {
             versionName = "${appVersion}l$betaSuffix"
             applicationId = "ch.threema.app.libre"
-            testApplicationId = "ch.threema.app.libre.test"
+            testApplicationId = "$applicationId.test"
             stringResValue("package_name", applicationId!!)
             setProductNames(
                 appName = "Threema Libre",

+ 2 - 2
app/src/green/java/ch/threema/app/compose/theme/color/BrandColor.kt

@@ -34,6 +34,6 @@ object BrandColor {
     const val SHADE_500 = 0xFF40E692
     const val SHADE_600 = 0xFF36D588
     const val SHADE_700 = 0xFF2CC47E
-    const val SHADE_800 = 0xFF0E9061
-    const val SHADE_900 = 0xFF0B734E
+    const val SHADE_800 = 0xFF0B734E
+    const val SHADE_900 = 0xFF00412A
 }

+ 2 - 2
app/src/hms/java/ch/threema/app/compose/theme/color/BrandColor.kt

@@ -34,6 +34,6 @@ object BrandColor {
     const val SHADE_500 = 0xFF40E692
     const val SHADE_600 = 0xFF36D588
     const val SHADE_700 = 0xFF2CC47E
-    const val SHADE_800 = 0xFF0E9061
-    const val SHADE_900 = 0xFF0B734E
+    const val SHADE_800 = 0xFF0B734E
+    const val SHADE_900 = 0xFF00412A
 }

+ 2 - 2
app/src/libre/java/ch/threema/app/compose/theme/color/BrandColor.kt

@@ -34,6 +34,6 @@ object BrandColor {
     const val SHADE_500 = 0xFF40E692
     const val SHADE_600 = 0xFF36D588
     const val SHADE_700 = 0xFF2CC47E
-    const val SHADE_800 = 0xFF0E9061
-    const val SHADE_900 = 0xFF0B734E
+    const val SHADE_800 = 0xFF0B734E
+    const val SHADE_900 = 0xFF00412A
 }

+ 2 - 3
app/src/libre/play/release-notes/de/default.txt

@@ -1,3 +1,2 @@
-- Behebung eines möglichen Absturzes beim Öffnen des Archivs
-- Behebung eines Fehlers beim Auswählen von Text in Nachrichten
-- Behebung eines Fehlers beim Erstellen von Backups
+- Anpassung der Farbgebung in der App, um die Lesbarkeit von Texten zu verbessern
+- Verschiedene Fehlerbehebungen und Verbesserungen

+ 2 - 3
app/src/libre/play/release-notes/en-US/default.txt

@@ -1,3 +1,2 @@
-- Fixed a possible crash that occurred when opening the archive
-- Fixed a bug that could occur when selecting text in messages
-- Fixed a bug that could occur when creating a backup
+- Adjusted the color scheme in the app to improve the readability of texts
+- Minor Bugfixes and improvements

+ 66 - 9
app/src/main/java/ch/threema/app/activities/EnterSerialActivity.java

@@ -196,6 +196,12 @@ public class EnterSerialActivity extends ThreemaActivity {
 
         // Always enable for work build
         setLoginButtonEnabled(true);
+
+        String presetServerUrl = getPresetOnPremServerUrlIfWhiteLabeled();
+        if (presetServerUrl != null) {
+            serverText.setText(presetServerUrl);
+            serverText.setEnabled(false);
+        }
     }
 
     private void handleUrlIntent(@Nullable Intent intent) {
@@ -229,6 +235,12 @@ public class EnterSerialActivity extends ThreemaActivity {
                 String password = AppRestrictionUtil.getStringRestriction(getString(R.string.restriction__license_password));
                 String server = AppRestrictionUtil.getStringRestriction(getString(R.string.restriction__onprem_server));
 
+                String presetServerUrl = getPresetOnPremServerUrlIfWhiteLabeled();
+                if (isServerUrlMismatch(presetServerUrl, server)) {
+                    onMDMServerUrlPresetMismatch();
+                    return;
+                }
+
                 if (!TestUtil.isEmptyOrNull(username) && !TestUtil.isEmptyOrNull(password)) {
                     check(new UserCredentials(username, password), server);
                 }
@@ -277,12 +289,18 @@ public class EnterSerialActivity extends ThreemaActivity {
         final String server = data.getQueryParameter("server");
 
         if (ConfigUtils.isOnPremBuild()) {
+            final String presetServerUrl = getPresetOnPremServerUrlIfWhiteLabeled();
+            if (isServerUrlMismatch(presetServerUrl, server)) {
+                onIntentServerUrlPresetMismatch();
+                return;
+            }
+
             if (!TestUtil.isEmptyOrNull(username) && !TestUtil.isEmptyOrNull(password) && !TestUtil.isEmptyOrNull(server)) {
                 check(new UserCredentials(username, password), server);
             } else {
                 licenseKeyOrUsernameText.setText(username);
                 passwordText.setText(password);
-                serverText.setText(server);
+                serverText.setText(presetServerUrl != null ? presetServerUrl : server);
             }
         } else {
             if (!TestUtil.isEmptyOrNull(username) && !TestUtil.isEmptyOrNull(password)) {
@@ -365,14 +383,7 @@ public class EnterSerialActivity extends ThreemaActivity {
     private void check(final LicenseService.Credentials credentials, String onPremServer) {
         if (ConfigUtils.isOnPremBuild()) {
             if (onPremServer != null) {
-                if (!onPremServer.startsWith("https://")) {
-                    onPremServer = "https://" + onPremServer;
-                }
-
-                if (!onPremServer.endsWith(".oppf")) {
-                    // Automatically expand hostnames to default provisioning URL
-                    onPremServer += "/prov/config.oppf";
-                }
+                onPremServer = getUrlToOppf(onPremServer);
             }
             preferenceService.setOnPremServer(onPremServer);
             preferenceService.setLicenseUsername(((UserCredentials) credentials).username);
@@ -419,6 +430,21 @@ public class EnterSerialActivity extends ThreemaActivity {
         }.execute();
     }
 
+    private void onIntentServerUrlPresetMismatch() {
+        logger.error("The intent's server url does not match the preset server url");
+        changeState(getString(R.string.error_preset_onprem_url_mismatch_intent));
+    }
+
+    private void onMDMServerUrlPresetMismatch() {
+        logger.error("The server url provided by MDM does not match the preset server url");
+        changeState(getString(R.string.error_preset_onprem_url_mismatch_mdm));
+        // Disable any input to keep the error message showing. Additionally, it wouldn't make sense
+        // to enter any credentials as long as a wrong mdm server url is set.
+        licenseKeyOrUsernameText.setEnabled(false);
+        passwordText.setEnabled(false);
+        this.setLoginButtonEnabled(false);
+    }
+
     private void changeState(String state) {
         this.stateTextView.setText(state);
     }
@@ -435,4 +461,35 @@ public class EnterSerialActivity extends ThreemaActivity {
         super.onNewIntent(intent);
         handleUrlIntent(intent);
     }
+
+    @Nullable
+    private String getPresetOnPremServerUrlIfWhiteLabeled() {
+        //noinspection ConstantValue
+        return ConfigUtils.isWhitelabelOnPremBuild(this) && BuildConfig.PRESET_OPPF_URL != null
+            ? BuildConfig.PRESET_OPPF_URL
+            : null;
+    }
+
+    @NonNull
+    private String getUrlToOppf(@NonNull String url) {
+        if (!url.startsWith("https://")) {
+            url = "https://" + url;
+        }
+
+        if (!url.endsWith(".oppf")) {
+            // Automatically expand hostnames to default provisioning URL
+            url += "/prov/config.oppf";
+        }
+
+        return url;
+    }
+
+    private boolean isServerUrlMismatch(@Nullable String presetServerUrl, @Nullable String serverUrl) {
+        if (presetServerUrl == null || serverUrl == null) {
+            return false;
+        }
+        @NonNull String canonicalPresetServerUrl = getUrlToOppf(presetServerUrl);
+        @NonNull String canonicalServerUrl = getUrlToOppf(serverUrl);
+        return !canonicalPresetServerUrl.equals(canonicalServerUrl);
+    }
 }

+ 0 - 1
app/src/main/java/ch/threema/app/activities/ThreemaActivity.java

@@ -66,7 +66,6 @@ public abstract class ThreemaActivity extends ThreemaAppCompatActivity {
     public static final int ACTIVITY_ID_PAINT = 20049;
     public static final int ACTIVITY_ID_PICK_MEDIA = 20050;
     public static final int ACTIVITY_ID_MANAGE_GROUP_LINKS = 20051;
-    final static public int ACTIVITY_ID_WORK_INTRO = 20052;
 
     public static final int RESULT_RESTART = 40005;
 

+ 6 - 1
app/src/main/java/ch/threema/app/activities/WorkIntroActivity.kt

@@ -35,6 +35,7 @@ import ch.threema.app.activities.wizard.components.WizardButtonXml
 import ch.threema.app.ui.InsetSides
 import ch.threema.app.ui.SpacingValues
 import ch.threema.app.ui.applyDeviceInsetsAsMargin
+import ch.threema.app.utils.ConfigUtils
 import ch.threema.app.utils.LinkifyUtil
 import ch.threema.app.utils.logScreenVisibility
 import ch.threema.base.utils.LoggingUtil
@@ -92,7 +93,11 @@ class WorkIntroActivity : ThreemaActivity() {
             .plus(getString(R.string.work_intro_more_link_text))
             .plus(HTML_LINK_FORMAT_TEMPLATE_POSTFIX)
 
-        val workInfoLink = getString(R.string.threema_work_url)
+        val workInfoLink = if (ConfigUtils.isOnPremBuild()) {
+            getString(R.string.threema_onprem_url)
+        } else {
+            getString(R.string.threema_work_url)
+        }
 
         val workInfoHtmlLink = String.format(
             workInfoLinkTemplate,

+ 20 - 3
app/src/main/java/ch/threema/app/backuprestore/csv/BackupService.java

@@ -629,6 +629,7 @@ public class BackupService extends Service {
         // Iterate over all contacts. Then backup every contact with the corresponding messages.
         try (final ByteArrayOutputStream contactBuffer = new ByteArrayOutputStream()) {
             try (final CSVWriter contactCsv = new CSVWriter(new OutputStreamWriter(contactBuffer), contactCsvHeader)) {
+                int contactCounter = 0;
                 for (final ContactModel contactModel : contactService.find(null)) {
                     if (!this.next("backup contact " + contactModel.getIdentity())) {
                         return false;
@@ -640,6 +641,8 @@ public class BackupService extends Service {
                     }
 
                     String identityId = getFormattedUniqueId();
+                    contactCounter++;
+                    logger.info("Back up contact #{}", contactCounter);
 
                     // Write contact
                     contactCsv.createRow()
@@ -659,7 +662,8 @@ public class BackupService extends Service {
                     // Back up contact profile pictures
                     if (this.config.backupAvatars()) {
                         try {
-                            if (!userService.getIdentity().equals(contactModel.getIdentity())) {
+                            if (!userService.isMe(contactModel.getIdentity())) {
+                                logger.info("Back up user defined profile picture for contact #{}", contactCounter);
                                 zipOutputStream.addFileFromInputStream(
                                     this.fileService.getUserDefinedProfilePictureStream(contactModel.getIdentity()),
                                     Tags.CONTACT_AVATAR_FILE_PREFIX + identityId,
@@ -672,6 +676,7 @@ public class BackupService extends Service {
                         }
 
                         try {
+                            logger.info("Back up contact defined profile picture for contact #{}", contactCounter);
                             zipOutputStream.addFileFromInputStream(
                                 this.fileService.getContactDefinedProfilePictureStream(contactModel.getIdentity()),
                                 Tags.CONTACT_PROFILE_PIC_FILE_PREFIX + identityId,
@@ -684,6 +689,7 @@ public class BackupService extends Service {
                     }
 
                     // Back up conversations
+                    logger.info("Back up messages for contact #{}", contactCounter);
                     try (final ByteArrayOutputStream messageBuffer = new ByteArrayOutputStream()) {
                         try (final CSVWriter messageCsv = new CSVWriter(new OutputStreamWriter(messageBuffer), messageCsvHeader)) {
 
@@ -691,12 +697,16 @@ public class BackupService extends Service {
                                 .getMessageModelFactory()
                                 .getByIdentityUnsorted(contactModel.getIdentity());
 
+                            logger.info("Found {} messages for contact #{}", messageModels.size(), contactCounter);
+
+                            long messageCounter = 0;
                             for (MessageModel messageModel : messageModels) {
                                 if (!this.next("backup message " + messageModel.getId())) {
                                     return false;
                                 }
 
                                 String apiMessageId = messageModel.getApiMessageId();
+                                messageCounter++;
 
                                 if ((apiMessageId != null && !apiMessageId.isEmpty()) || messageModel.getType() == MessageType.VOIP_STATUS) {
                                     messageCsv.createRow()
@@ -727,10 +737,16 @@ public class BackupService extends Service {
                                     zipOutputStream,
                                     Tags.MESSAGE_MEDIA_FILE_PREFIX,
                                     Tags.MESSAGE_MEDIA_THUMBNAIL_FILE_PREFIX,
-                                    messageModel);
+                                    messageModel
+                                );
+
+                                if ((messageCounter < 1000 && messageCounter % 100 == 0) || (messageCounter < 50000 && messageCounter % 1000 == 0)) {
+                                    logger.info("Backed up {} messages for contact #{}", messageCounter, contactCounter);
+                                }
                             }
                         }
 
+                        logger.info("Writing contact messages file");
                         zipOutputStream.addFileFromInputStream(
                             new ByteArrayInputStream(messageBuffer.toByteArray()),
                             Tags.MESSAGE_FILE_PREFIX + identityId + Tags.CSV_FILE_POSTFIX,
@@ -740,6 +756,7 @@ public class BackupService extends Service {
                 }
             }
 
+            logger.info("Writing contacts file");
             zipOutputStream.addFileFromInputStream(
                 new ByteArrayInputStream(contactBuffer.toByteArray()),
                 Tags.CONTACTS_FILE_NAME + Tags.CSV_FILE_POSTFIX,
@@ -1069,7 +1086,7 @@ public class BackupService extends Service {
     private boolean backupBallots(
         @NonNull FileHandlingZipOutputStream zipOutputStream
     ) throws ThreemaException, IOException {
-        logger.info("Backup polls (formerly known as 'ballots'");
+        logger.info("Backup polls (formerly known as 'ballots')");
         final String[] ballotCsvHeader = {
             Tags.TAG_BALLOT_ID,
             Tags.TAG_BALLOT_API_ID,

+ 37 - 50
app/src/main/java/ch/threema/app/compose/common/buttons/ButtonPrimary.kt

@@ -22,19 +22,16 @@
 package ch.threema.app.compose.common.buttons
 
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.heightIn
-import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.Button
 import androidx.compose.material3.ButtonColors
 import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.LocalContentColor
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.tooling.preview.Preview
@@ -108,9 +105,7 @@ private fun ButtonPrimaryBase(
         enabled = enabled,
     ) {
         ThemedText(
-            modifier = Modifier.alpha(
-                if (enabled) 1f else .4f,
-            ),
+            color = LocalContentColor.current,
             text = text,
             style = textStyle,
             maxLines = maxLines,
@@ -119,69 +114,61 @@ private fun ButtonPrimaryBase(
     }
 }
 
-@Preview(showSystemUi = true)
+@Preview
+@Composable
+fun ButtonPrimary_Preview_LongText() {
+    ThreemaThemePreview {
+        ButtonPrimary(
+            onClick = {},
+            maxLines = 2,
+            text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sapien magna, efficitur a urna efficitur, varius " +
+                "fermentum arcu. Donec rhoncus erat sem, vel ultrices sapien pharetra sit amet.",
+        )
+    }
+}
+
+@Preview
 @Composable
 fun ButtonPrimary_Preview() {
     ThreemaThemePreview {
-        Scaffold(
-            modifier = Modifier.fillMaxSize(),
-        ) { paddingValues ->
-            ButtonPrimary(
-                modifier = Modifier.padding(paddingValues),
-                onClick = {},
-                text = "Preview",
-            )
-        }
+        ButtonPrimary(
+            onClick = {},
+            text = "Preview",
+        )
     }
 }
 
-@Preview(showSystemUi = true)
+@Preview
 @Composable
 fun ButtonPrimary_Preview_Disabled() {
     ThreemaThemePreview {
-        Scaffold(
-            modifier = Modifier.fillMaxSize(),
-        ) { paddingValues ->
-            ButtonPrimary(
-                modifier = Modifier.padding(paddingValues),
-                onClick = {},
-                text = "Preview",
-                enabled = false,
-            )
-        }
+        ButtonPrimary(
+            onClick = {},
+            text = "Preview",
+            enabled = false,
+        )
     }
 }
 
-@Preview(showSystemUi = true)
+@Preview
 @Composable
 fun ButtonPrimary_Preview_FullWidth() {
     ThreemaThemePreview {
-        Scaffold(
-            modifier = Modifier.fillMaxSize(),
-        ) { paddingValues ->
-            ButtonPrimary(
-                modifier = Modifier
-                    .fillMaxWidth()
-                    .padding(paddingValues),
-                onClick = {},
-                text = "Preview",
-            )
-        }
+        ButtonPrimary(
+            modifier = Modifier.fillMaxWidth(),
+            onClick = {},
+            text = "Preview",
+        )
     }
 }
 
-@Preview(showSystemUi = true)
+@Preview
 @Composable
 fun ButtonPrimarySmall_Preview() {
     ThreemaThemePreview {
-        Scaffold(
-            modifier = Modifier.fillMaxSize(),
-        ) { paddingValues ->
-            ButtonPrimarySmall(
-                modifier = Modifier.padding(paddingValues),
-                onClick = {},
-                text = "Preview",
-            )
-        }
+        ButtonPrimarySmall(
+            onClick = {},
+            text = "Preview",
+        )
     }
 }

+ 5 - 5
app/src/main/java/ch/threema/app/compose/theme/color/ColorsLight.kt

@@ -26,16 +26,16 @@ import androidx.compose.ui.graphics.Color
 object ColorsLight : ComposeColorPaletteLight() {
 
     // Primary
-    override val primary = Color(BrandColor.SHADE_700)
+    override val primary = Color(BrandColor.SHADE_800)
     override val onPrimary = Color(0xFFFFFFFF)
-    override val primaryContainer = Color(BrandColor.SHADE_700)
+    override val primaryContainer = Color(BrandColor.SHADE_800)
     override val onPrimaryContainer = Color(0xFFFFFFFF)
-    override val inversePrimary = Color(BrandColor.SHADE_500)
+    override val inversePrimary = Color(BrandColor.SHADE_600)
 
     // Secondary
-    override val secondary = Color(BrandColor.SHADE_300)
+    override val secondary = Color(BrandColor.SHADE_400)
     override val onSecondary = Color(BrandColor.SHADE_900)
-    override val secondaryContainer = Color(BrandColor.SHADE_300)
+    override val secondaryContainer = Color(BrandColor.SHADE_400)
     override val onSecondaryContainer = Color(BrandColor.SHADE_900)
 
     // Secondary

+ 37 - 3
app/src/main/java/ch/threema/app/home/HomeActivity.java

@@ -633,9 +633,8 @@ public class HomeActivity extends ThreemaAppCompatActivity implements
         }
 
         if (ConfigUtils.isSerialLicensed() && !ConfigUtils.isSerialLicenseValid()) {
-            boolean isInstalledFromStore = ConfigUtils.isInstalledFromStore(ThreemaApplication.getAppContext());
-            if (ConfigUtils.isWorkBuild() && !ConfigUtils.isWorkRestricted() && !hasIdentity() && isInstalledFromStore) {
-                startActivityForResult(new Intent(this, WorkIntroActivity.class), ThreemaActivity.ACTIVITY_ID_WORK_INTRO);
+            if (shouldShowWorkIntroScreen()) {
+                startActivity(new Intent(this, WorkIntroActivity.class));
             } else {
                 startActivityForResult(new Intent(this, EnterSerialActivity.class), ThreemaActivity.ACTIVITY_ID_ENTER_SERIAL);
             }
@@ -716,6 +715,41 @@ public class HomeActivity extends ThreemaAppCompatActivity implements
         }
     }
 
+    /**
+     * Check whether the work intro screen should be shown. The work intro screen contains a notice
+     * to direct users to the private version of the app in case it is possible that they installed
+     * the work or onprem app by mistake. In certain cases we can rule out an oversight and skip the
+     * screen.
+     *
+     * @return true if the screen should be shown
+     */
+    private boolean shouldShowWorkIntroScreen() {
+        // Don't show the screen if the app is already set up with an identity.
+        if (ThreemaApplication.requireServiceManager().getUserService().hasIdentity()) {
+            return false;
+        }
+
+        // If it is no work (including onprem) build, we should not show the screen.
+        if (!ConfigUtils.isWorkBuild()) {
+            return false;
+        }
+
+        // If the app is restricted, then we should skip the screen as it is very likely intended to
+        // use the work or onprem app.
+        if (ConfigUtils.isWorkRestricted()) {
+            return false;
+        }
+
+        // If the app is not installed from a store, the chance that the private app should be used
+        // instead is smaller and therefore we should skip the screen.
+        if (!ConfigUtils.isInstalledFromStore(this)) {
+            return false;
+        }
+
+        // On whitelabel onprem build it doesn't make sense to show the work intro screen.
+        return !ConfigUtils.isWhitelabelOnPremBuild(this);
+    }
+
     private void reconfigureSafe(@NonNull ThreemaSafeService threemaSafeService, @NonNull ThreemaSafeMDMConfig newConfig) {
         // dispose of old backup, if any
         try {

+ 0 - 7
app/src/main/java/ch/threema/app/multidevice/wizard/steps/LinkNewDeviceEmojiSelectionView.kt

@@ -23,12 +23,10 @@ package ch.threema.app.multidevice.wizard.steps
 
 import android.annotation.SuppressLint
 import android.content.Context
-import android.content.res.ColorStateList
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.widget.ImageView
 import ch.threema.app.R
-import ch.threema.app.utils.ConfigUtils
 import ch.threema.base.utils.LoggingUtil
 import com.google.android.material.card.MaterialCardView
 
@@ -54,11 +52,6 @@ class LinkNewDeviceEmojiSelectionView : MaterialCardView {
     init {
         LayoutInflater.from(context).inflate(R.layout.view_emoji_selection, this, true)
 
-        setCardBackgroundColor(
-            ColorStateList.valueOf(
-                ConfigUtils.getColorFromAttribute(context, R.attr.colorPrimaryContainer),
-            ),
-        )
         strokeWidth = 0
         cardElevation = 0F
 

+ 8 - 10
app/src/main/java/ch/threema/app/preference/SettingsAdvancedOptionsFragment.java

@@ -276,23 +276,21 @@ public class SettingsAdvancedOptionsFragment extends ThreemaPreferenceFragment i
         // Do not show send log preference on on prem builds
         if (ConfigUtils.isOnPremBuild()) {
             loggingCategory.removePreference(sendLogPreference);
-
-            // Show share options
-            exportLogPreference.setOnPreferenceClickListener(preference -> {
-                var success = ShareUtil.shareLogfile(requireContext());
-                if (!success) {
-                    showToast(requireContext(), R.string.try_again);
-                }
-                return true;
-            });
         } else {
-            loggingCategory.removePreference(exportLogPreference);
             sendLogPreference.setOnPreferenceClickListener(preference -> {
                 prepareSendLogfile();
                 return true;
             });
         }
 
+        exportLogPreference.setOnPreferenceClickListener(preference -> {
+            var success = ShareUtil.shareLogfile(requireContext());
+            if (!success) {
+                showToast(requireContext(), R.string.try_again);
+            }
+            return true;
+        });
+
         Preference resetPushPreference = getPref(getResources().getString(R.string.preferences__reset_push));
         resetPushPreference.setOnPreferenceClickListener(preference -> {
             if (pushServicesInstalled) {

+ 3 - 3
app/src/main/java/ch/threema/app/restrictions/ApplyAppRestrictionsWorker.kt

@@ -42,10 +42,10 @@ import ch.threema.app.R
 import ch.threema.app.ThreemaApplication.Companion.awaitServiceManagerWithTimeout
 import ch.threema.app.multidevice.MultiDeviceManager
 import ch.threema.app.preference.service.GroupCallPolicySetting
-import ch.threema.app.preference.service.KeyboardDataCollectionPolicySetting
 import ch.threema.app.preference.service.O2oCallPolicySetting
 import ch.threema.app.preference.service.O2oCallVideoPolicySetting
 import ch.threema.app.preference.service.PreferenceService
+import ch.threema.app.preference.service.ScreenshotPolicySetting
 import ch.threema.app.preference.service.UnknownContactPolicySetting
 import ch.threema.app.restrictions.ApplyAppRestrictionsWorker.RestrictionToPreferenceValueMapper.Invert
 import ch.threema.app.restrictions.ApplyAppRestrictionsWorker.RestrictionToPreferenceValueMapper.Keep
@@ -107,7 +107,7 @@ class ApplyAppRestrictionsWorker(
             // We do not retry the work as a transaction exception will probably be thrown on retries as well.
             return Result.failure()
         } catch (e: Exception) {
-            logger.error("Error while mapping restrictions to preferences")
+            logger.error("Error while mapping restrictions to preferences", e)
             return Result.retry()
         }
 
@@ -238,7 +238,7 @@ class ApplyAppRestrictionsWorker(
             context = context,
             sharedPreferences = sharedPreferences,
             restrictionKeyRes = R.string.restriction__disable_screenshots,
-            preferenceKeyRes = KeyboardDataCollectionPolicySetting.preferenceKeyStringRes,
+            preferenceKeyRes = ScreenshotPolicySetting.preferenceKeyStringRes,
             restrictionToPreferenceValueMapper = Keep,
             settingsSyncCreator = { settingsBuilder, disableScreenshotsRestriction ->
                 settingsBuilder.setScreenshotPolicy(

+ 1 - 0
app/src/main/java/ch/threema/app/services/UserServiceImpl.java

@@ -543,6 +543,7 @@ public class UserServiceImpl implements UserService, CreateIdentityRequestDataIn
 
     @Override
     public String setPublicNickname(@Nullable String publicNickname, @NonNull TriggerSource triggerSource) {
+        logger.info("Setting nickname");
         final @NonNull String oldNickname = this.identityStore.getPublicNickname();
         // truncate string into a 32 byte length string
         // fix #ANDR-530

+ 47 - 22
app/src/main/java/ch/threema/app/utils/AndroidContactUtil.java

@@ -141,8 +141,8 @@ public class AndroidContactUtil {
         final String lastName;
 
         public ContactName(@Nullable String firstName, @Nullable String lastName) {
-            this.firstName = firstName != null ? firstName.trim() : firstName;
-            this.lastName = lastName != null ? lastName.trim() : lastName;
+            this.firstName = firstName != null ? firstName.trim() : null;
+            this.lastName = lastName != null ? lastName.trim() : null;
         }
     }
 
@@ -234,6 +234,7 @@ public class AndroidContactUtil {
             }
         }
 
+        // Note that directly logging the lookup key and the contact uri is ok for debug level.
         logger.debug("Unable to get avatar for {} lookupKey = {} contactUri = {}", contactModel.getIdentity(), androidContactLookupKey, contactUri);
     }
 
@@ -255,14 +256,14 @@ public class AndroidContactUtil {
         }
         Uri namedContactUri = getAndroidContactUri(contactModel);
         if (namedContactUri == null) {
-            logger.info("Unable to get android contact uri for {} lookupKey = {}", contactModel.getIdentity(), data.androidContactLookupKey);
+            logger.info("Unable to get android contact uri for {} obfuscatedLookupKey = {}", contactModel.getIdentity(), getObfuscatedAndroidContactLookupKey(data));
             return;
         }
 
         ContactName contactName = getContactName(namedContactUri);
 
         if (contactName == null) {
-            logger.info("Unable to get contact name for {} lookupKey = {} namedUri = {}", contactModel.getIdentity(), data.androidContactLookupKey, namedContactUri);
+            logger.info("Unable to get contact name for {} obfuscatedLookupKey = {}", contactModel.getIdentity(), getObfuscatedAndroidContactLookupKey(data));
             // remove contact link to unresolvable contact
             contactModel.removeAndroidContactLink();
             throw new ThreemaException("Unable to get contact name");
@@ -273,8 +274,8 @@ public class AndroidContactUtil {
         }
 
         if (!data.firstName.equals(contactName.firstName) || !data.lastName.equals(contactName.lastName)) {
-            logger.info("Updating name of contact. identity={}, lookupKey={}, namedUri={}",
-                contactModel.getIdentity(), data.androidContactLookupKey, namedContactUri);
+            logger.info("Updating name of contact. identity={}, obfuscatedLookupKey={}",
+                contactModel.getIdentity(), getObfuscatedAndroidContactLookupKey(data));
             contactModel.setNameFromLocal(contactName.firstName, contactName.lastName);
         }
     }
@@ -291,19 +292,18 @@ public class AndroidContactUtil {
     @RequiresPermission(Manifest.permission.READ_CONTACTS)
     @Nullable
     private ContactName getContactName(Uri contactUri) {
-        if (!TestUtil.required(this.contentResolver)) {
+        if (this.contentResolver == null) {
+            logger.error("Cannot get contact name as content resolver is null");
             return null;
         }
 
         ContactName contactName = null;
-        Cursor nameCursor = null;
-        try {
-            nameCursor = this.contentResolver.query(
-                contactUri,
-                NAME_PROJECTION,
-                null,
-                null,
-                null);
+        try (Cursor nameCursor = this.contentResolver.query(
+            contactUri,
+            NAME_PROJECTION,
+            null,
+            null,
+            null)) {
 
             if (nameCursor != null && nameCursor.moveToFirst()) {
                 long contactId = nameCursor.getLong(nameCursor.getColumnIndex(ContactsContract.Contacts._ID));
@@ -311,6 +311,7 @@ public class AndroidContactUtil {
 
                 // fallback
                 if (contactName.firstName == null && contactName.lastName == null) {
+                    logger.info("Falling back to alternative sort key.");
                     //lastname, firstname
                     String alternativeSortKey = nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.Contacts.SORT_KEY_ALTERNATIVE));
 
@@ -326,19 +327,17 @@ public class AndroidContactUtil {
                         }
                     } else {
                         // no contact name found
-                        logger.info("No contact name found for contact ID {} uri = {}", contactId, contactUri.toString());
+                        logger.info("No contact name found for contact ID {}", contactId);
                         return null;
                     }
+                } else {
+                    logger.info("Getting structured name for contact was successful");
                 }
             } else {
-                logger.info("Contact not found: {}", contactUri.toString());
+                logger.info("Contact not found");
             }
         } catch (PatternSyntaxException e) {
             logger.error("Exception", e);
-        } finally {
-            if (nameCursor != null) {
-                nameCursor.close();
-            }
         }
         return contactName;
     }
@@ -403,7 +402,7 @@ public class AndroidContactUtil {
 
     @RequiresPermission(Manifest.permission.READ_CONTACTS)
     private @NonNull Map<String, String> getStructuredNameByContactId(long id) {
-        Map<String, String> structuredName = new TreeMap<String, String>();
+        Map<String, String> structuredName = new TreeMap<>();
 
         Cursor cursor = this.contentResolver.query(
             ContactsContract.Data.CONTENT_URI,
@@ -778,4 +777,30 @@ public class AndroidContactUtil {
         }
         return false;
     }
+
+    @Nullable
+    private static String getObfuscatedAndroidContactLookupKey(@Nullable ContactModelData contactModelData) {
+        if (contactModelData == null) {
+            return null;
+        }
+        return getObfuscatedAndroidContactLookupKey(contactModelData.androidContactLookupKey);
+    }
+
+    @Nullable
+    private static String getObfuscatedAndroidContactLookupKey(@Nullable String androidContactLookupKey) {
+        if (androidContactLookupKey == null) {
+            return null;
+        }
+        // The lookup key and contact id are separated by a slash
+        int splitIndex = androidContactLookupKey.lastIndexOf('/');
+        if (splitIndex == -1) {
+            logger.warn("Unexpected lookup key format as it does not contain '/'");
+            return "unexpected-" + androidContactLookupKey.hashCode();
+        }
+        // Obfuscate the lookup key as it may contain sensitive data
+        int obfuscatedLookupKey = androidContactLookupKey.substring(0, splitIndex).hashCode();
+        String contactId = androidContactLookupKey.substring(splitIndex);
+        // Concatenate the obfuscated lookup key with the raw contact id
+        return obfuscatedLookupKey + contactId;
+    }
 }

+ 4 - 0
app/src/main/java/ch/threema/app/utils/ConfigUtils.java

@@ -721,6 +721,10 @@ public class ConfigUtils {
         return BuildFlavor.getCurrent().getLicenseType().equals(BuildFlavor.LicenseType.ONPREM);
     }
 
+    public static boolean isWhitelabelOnPremBuild(@NonNull Context context) {
+        return isOnPremBuild() && !context.getPackageName().equals("ch.threema.app.onprem");
+    }
+
     public static boolean isDemoOPServer(@NonNull PreferenceService preferenceService) {
         return preferenceService.getOnPremServer() != null && preferenceService.getOnPremServer().toLowerCase().contains(".3ma.ch/");
     }

+ 10 - 2
app/src/main/java/ch/threema/app/voip/activities/CallActivity.java

@@ -170,13 +170,14 @@ import java8.util.concurrent.CompletableFuture;
  */
 public class CallActivity extends ThreemaActivity implements
     BottomSheetAbstractDialog.BottomSheetDialogCallback,
+    GenericAlertDialog.DialogClickListener,
     SensorListener,
     LifecycleOwner {
     private static final Logger logger = LoggingUtil.getThreemaLogger("CallActivity");
     private static final String LIFETIME_SERVICE_TAG = "CallActivity";
     private static final String SENSOR_TAG_CALL = "voipcall";
     public static final String EXTRA_ACCEPT_INCOMING_CALL = "ACCEPT_INCOMING_CALL";
-    private static final String DIALOG_TAG_OK = "ok";
+    private static final String DIALOG_TAG_CONNECTION_FAILED = "connection_failed";
 
     // saved activity states
     private static final String BUNDLE_ACTIVITY_MODE = "activityMode";
@@ -465,7 +466,7 @@ public class CallActivity extends ThreemaActivity implements
                     case ACTION_CONNECTING_FAILED:
                         if (!isDestroyed()) {
                             GenericAlertDialog.newInstance(R.string.error, R.string.voip_connection_failed, R.string.ok, 0)
-                                .show(getSupportFragmentManager(), DIALOG_TAG_OK);
+                                .show(getSupportFragmentManager(), DIALOG_TAG_CONNECTION_FAILED);
                         }
                         break;
                     case ACTION_RECONNECTING:
@@ -2342,6 +2343,13 @@ public class CallActivity extends ThreemaActivity implements
     //endregion
 
 
+    @Override
+    public void onYes(String tag, Object data) {
+        if (tag.equals(DIALOG_TAG_CONNECTION_FAILED)) {
+            abortWithError();
+        }
+    }
+
     @Override
     public void finish() {
         KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);

+ 1 - 1
app/src/main/res/color-night-v21/bubble_receive_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Delete -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_400" android:state_pressed="true" />
+    <item android:color="@color/brand_500" android:state_pressed="true" />
     <item android:color="@color/brand_500" android:state_activated="true" />
     <item android:color="@color/brand_grey_700" />
 </selector>

+ 1 - 1
app/src/main/res/color-night-v21/bubble_send_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Delete -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_400" android:state_pressed="true" />
+    <item android:color="@color/brand_500" android:state_pressed="true" />
     <item android:color="@color/brand_500" android:state_activated="true" />
     <item android:color="@color/brand_grey_800" />
 </selector>

+ 1 - 1
app/src/main/res/color-night-v21/bubble_status_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Delete -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_400" android:state_pressed="true" />
+    <item android:color="@color/brand_500" android:state_pressed="true" />
     <item android:color="@color/brand_500" android:state_activated="true" />
     <item android:color="@color/brand_grey_800" />
 </selector>

+ 0 - 7
app/src/main/res/color-night-v22/bubble_send_text_colorstatelist.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- TODO(ANDR-3888) Move to colors-night folder -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorOnSecondaryContainer" android:state_pressed="true" />
-    <item android:color="?attr/colorOnSecondaryContainer" android:state_activated="true" />
-    <item android:color="?attr/colorOnSurface" />
-</selector>

+ 2 - 2
app/src/main/res/color-night-v22/bubble_receive_colorstatelist.xml → app/src/main/res/color-night-v23/bubble_receive_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- TODO(ANDR-3888) Move to colors-night folder -->
+<!-- TODO(ANDR-3888) Move to default colors-night folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorSecondaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorSurfaceContainerHigh" />
 </selector>

+ 2 - 2
app/src/main/res/color-night-v22/bubble_send_colorstatelist.xml → app/src/main/res/color-night-v23/bubble_send_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- TODO(ANDR-3888) Move to colors-night folder -->
+<!-- TODO(ANDR-3888) Move to default colors-night folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorSecondaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorSurfaceContainer" />
 </selector>

+ 7 - 0
app/src/main/res/color-night-v23/bubble_send_text_colorstatelist.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- TODO(ANDR-3888) Move to default colors-night folder -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_activated="true" />
+    <item android:color="?attr/colorOnSurface" />
+</selector>

+ 7 - 0
app/src/main/res/color-night-v23/bubble_status_colorstatelist.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- TODO(ANDR-3888) Move to default colors-night folder -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?attr/colorPrimaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorPrimaryContainer" android:state_activated="true" />
+    <item android:color="?attr/colorSurfaceContainer" />
+</selector>

+ 2 - 2
app/src/main/res/color-v21/bubble_receive_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Delete -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_300" android:state_pressed="true" />
-    <item android:color="@color/brand_700" android:state_activated="true" />
+    <item android:color="@color/brand_800" android:state_pressed="true" />
+    <item android:color="@color/brand_800" android:state_activated="true" />
     <item android:color="@color/brand_grey_100" />
 </selector>

+ 2 - 2
app/src/main/res/color-v21/bubble_send_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Delete -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_300" android:state_pressed="true" />
-    <item android:color="@color/brand_700" android:state_activated="true" />
+    <item android:color="@color/brand_800" android:state_pressed="true" />
+    <item android:color="@color/brand_800" android:state_activated="true" />
     <item android:color="@color/brand_100" />
 </selector>

+ 2 - 2
app/src/main/res/color-v21/bubble_status_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Delete -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_300" android:state_pressed="true" />
-    <item android:color="@color/brand_700" android:state_activated="true" />
+    <item android:color="@color/brand_800" android:state_pressed="true" />
+    <item android:color="@color/brand_800" android:state_activated="true" />
     <item android:color="@color/brand_grey_50" />
 </selector>

+ 1 - 1
app/src/main/res/color-v22/bubble_receive_colorstatelist.xml → app/src/main/res/color-v23/bubble_receive_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Move to to default color folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorSecondaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorSurfaceContainer" />
 </selector>

+ 1 - 1
app/src/main/res/color-v22/bubble_send_colorstatelist.xml → app/src/main/res/color-v23/bubble_send_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Move to to default color folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorSecondaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorTertiaryContainer" />
 </selector>

+ 1 - 1
app/src/main/res/color-v22/bubble_status_colorstatelist.xml → app/src/main/res/color-v23/bubble_status_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Move to to default color folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorSecondaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorSurfaceContainer" />
 </selector>

+ 2 - 2
app/src/main/res/color/bubble_receive_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Replace with dynamically colored version from colors-v22 folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_300" android:state_pressed="true" />
-    <item android:color="@color/brand_700" android:state_activated="true" />
+    <item android:color="@color/brand_800" android:state_pressed="true" />
+    <item android:color="@color/brand_800" android:state_activated="true" />
     <item android:color="@color/brand_grey_100" />
 </selector>

+ 1 - 1
app/src/main/res/color/bubble_receive_text_colorstatelist.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorOnSecondaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorOnPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorOnSurface" />
 </selector>

+ 2 - 2
app/src/main/res/color/bubble_send_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Replace with dynamically colored version from colors-v22 folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_300" android:state_pressed="true" />
-    <item android:color="@color/brand_700" android:state_activated="true" />
+    <item android:color="@color/brand_800" android:state_pressed="true" />
+    <item android:color="@color/brand_800" android:state_activated="true" />
     <item android:color="@color/brand_100" />
 </selector>

+ 2 - 2
app/src/main/res/color/bubble_send_text_colorstatelist.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorOnSecondaryContainer" android:state_pressed="true" />
-    <item android:color="?attr/colorOnSecondaryContainer" android:state_activated="true" />
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorOnTertiaryContainer" />
 </selector>

+ 2 - 2
app/src/main/res/color/bubble_status_colorstatelist.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- TODO(ANDR-3888) Replace with dynamically colored version from colors-v22 folder -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/brand_300" android:state_pressed="true" />
-    <item android:color="@color/brand_700" android:state_activated="true" />
+    <item android:color="@color/brand_800" android:state_pressed="true" />
+    <item android:color="@color/brand_800" android:state_activated="true" />
     <item android:color="@color/brand_grey_50" />
 </selector>

+ 1 - 1
app/src/main/res/color/bubble_sticker_colorstatelist.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorSecondaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorPrimaryContainer" android:state_activated="true" />
     <item android:color="@android:color/transparent" />
 </selector>

+ 2 - 1
app/src/main/res/color/bubble_text_link_colorstatelist.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_activated="true" android:color="?attr/colorOnPrimary" />
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_pressed="true" />
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_activated="true" />
     <item android:color="?android:attr/textColorLink" />
 </selector>

+ 1 - 0
app/src/main/res/color/bubble_text_quote_colorstatelist.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorOnPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorOnSurface" />
 </selector>

+ 1 - 0
app/src/main/res/color/bubble_text_status_colorstatelist.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?attr/colorOnPrimaryContainer" android:state_pressed="true" />
     <item android:color="?attr/colorOnPrimaryContainer" android:state_activated="true" />
     <item android:color="?attr/colorOnSurface" />
 </selector>

+ 2 - 2
app/src/main/res/color/emojireactions_background_colorstatelist.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:color="@color/emojireactions_background_pressed" />
-    <item android:state_checked="true" android:color="@color/emojireactions_background_checked" />
+    <item android:color="@color/emojireactions_background_pressed" android:state_pressed="true" />
+    <item android:color="@color/emojireactions_background_checked" android:state_checked="true" />
     <item android:color="@color/emojireactions_background" />
 </selector>

+ 1 - 1
app/src/main/res/drawable-night/bubble_fade_recv_selector.xml

@@ -2,7 +2,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
         <shape android:shape="rectangle">
-            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorSecondaryContainer" />
+            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorPrimaryContainer" />
         </shape>
     </item>
     <item android:state_activated="true">

+ 18 - 0
app/src/main/res/drawable-night/bubble_fade_send_selector.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorPrimaryContainer" />
+        </shape>
+    </item>
+    <item android:state_activated="true">
+        <shape android:shape="rectangle">
+            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorPrimaryContainer" />
+        </shape>
+    </item>
+    <item>
+        <shape android:shape="rectangle">
+            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorSurfaceContainer" />
+        </shape>
+    </item>
+</selector>

+ 1 - 1
app/src/main/res/drawable/bubble_fade_recv_selector.xml

@@ -2,7 +2,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
         <shape android:shape="rectangle">
-            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorSecondaryContainer" />
+            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorPrimaryContainer" />
         </shape>
     </item>
     <item android:state_activated="true">

+ 1 - 1
app/src/main/res/drawable/bubble_fade_send_selector.xml

@@ -2,7 +2,7 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
         <shape android:shape="rectangle">
-            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorSecondaryContainer" />
+            <gradient android:angle="90" android:endColor="#00000000" android:startColor="?attr/colorPrimaryContainer" />
         </shape>
     </item>
     <item android:state_activated="true">

+ 0 - 22
app/src/main/res/drawable/ic_app_icon_consumer.xml

@@ -1,22 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="256dp"
-    android:viewportHeight="1024"
-    android:viewportWidth="1024"
-    android:width="256dp">
-
-    <path
-        android:fillColor="#323232"
-        android:fillType="evenOdd"
-        android:pathData="M85,0h854c47,0 85,38.1 85,85v854c0,47 -38.1,85 -85,85H85c-47,0 -85,-38.1 -85,-85V85C0,38.1 38.1,0 85,0z" />
-
-    <path
-        android:fillColor="#FFFFFF"
-        android:fillType="evenOdd"
-        android:pathData="M367.8,688.8L203,730l35.2,-140.9c-34.9,-46 -55.2,-101.2 -55.2,-160.6C183,268.6 330.3,139 512,139s329,129.6 329,289.5S693.7,718 512,718C460.3,718 411.4,707.5 367.8,688.8L367.8,688.8zM418.7,404.5H415c-8.3,0 -15,6.7 -15,15V551c0,8.3 6.7,15 15,15h194c8.3,0 15,-6.7 15,-15V419.5c0,-8.3 -6.7,-15 -15,-15h-3.7v-37.3c0,-51.4 -41.8,-93.2 -93.4,-93.2c-51.5,0 -93.3,41.8 -93.3,93.2v37.3H418.7zM568,404.5H456v-37.3c0,-30.9 25.1,-55.9 56,-55.9c31,0 56,25.1 56,55.9C568,387.8 568,400.2 568,404.5z" />
-
-    <path
-        android:fillColor="#05A63F"
-        android:fillType="evenOdd"
-        android:pathData="M568,848c0,30.9 -25,56 -56,56c-30.9,0 -55.9,-25.1 -55.9,-56s25,-56 55.9,-56S568,817.1 568,848zM366,848c0,30.9 -25,56 -56,56c-30.9,0 -55.9,-25.1 -55.9,-56s25,-56 55.9,-56C341,792 366,817.1 366,848zM769.9,848c0,30.9 -25,56 -56,56c-30.9,0 -55.9,-25.1 -55.9,-56s25,-56 55.9,-56C744.9,792 769.9,817.1 769.9,848z" />
-
-</vector>

+ 31 - 0
app/src/main/res/drawable/ic_app_icon_private.xml

@@ -0,0 +1,31 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="77.53dp"
+    android:height="77.53dp"
+    android:viewportWidth="77.53"
+    android:viewportHeight="77.53">
+  <path
+      android:pathData="M18.48,0L59.05,0A18.48,18.48 0,0 1,77.53 18.48L77.53,59.05A18.48,18.48 0,0 1,59.05 77.53L18.48,77.53A18.48,18.48 0,0 1,0 59.05L0,18.48A18.48,18.48 0,0 1,18.48 0z"
+      android:strokeWidth="0"
+      android:fillColor="#000"/>
+  <path
+      android:pathData="M26.82,64.1m-3.81,0a3.81,3.81 0,1 1,7.62 0a3.81,3.81 0,1 1,-7.62 0"
+      android:strokeWidth="0"
+      android:fillColor="#40e692"/>
+  <path
+      android:pathData="M51.72,64.1m-3.81,0a3.81,3.81 0,1 1,7.62 0a3.81,3.81 0,1 1,-7.62 0"
+      android:strokeWidth="0"
+      android:fillColor="#40e692"/>
+  <path
+      android:pathData="M39.27,64.1m-3.81,0a3.81,3.81 0,1 1,7.62 0a3.81,3.81 0,1 1,-7.62 0"
+      android:strokeWidth="0"
+      android:fillColor="#40e692"/>
+  <path
+      android:pathData="M38.76,9.62c-12.5,0 -22.68,10.17 -22.68,22.68 0,4.96 1.6,9.56 4.32,13.3l-2.83,8.42 8.71,-2.79c3.58,2.37 7.87,3.75 12.48,3.75 12.51,0 22.68,-10.17 22.68,-22.68s-10.17,-22.68 -22.68,-22.68Z"
+      android:strokeWidth="0"
+      android:fillColor="#fff"
+      android:fillType="evenOdd"/>
+  <path
+      android:pathData="M45.49,29.87h-0.2v-3.05c0,-3.6 -2.93,-6.52 -6.52,-6.52s-6.52,2.93 -6.52,6.52v3.05h-0.2c-1.14,0 -2.06,0.92 -2.06,2.06v8.23c0,1.14 0.92,2.06 2.06,2.06h13.44c1.14,0 2.06,-0.92 2.06,-2.06v-8.23c0,-1.14 -0.92,-2.06 -2.06,-2.06ZM34.91,26.81c0,-2.12 1.73,-3.85 3.85,-3.85s3.85,1.73 3.85,3.85v3.05h-7.7v-3.05Z"
+      android:strokeWidth="0"
+      android:fillColor="#000"/>
+</vector>

+ 1 - 0
app/src/main/res/layout/activity_permission_request.xml

@@ -39,6 +39,7 @@
         android:layout_height="0dp"
         android:layout_marginTop="16dp"
         android:padding="16dp"
+        android:background="@android:color/transparent"
         app:layout_constraintBottom_toTopOf="@id/permission_continue"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"

+ 1 - 0
app/src/main/res/layout/activity_server_message.xml

@@ -9,6 +9,7 @@
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
+        android:background="@android:color/transparent"
         android:clipToPadding="false"
         android:padding="@dimen/grid_unit_x2">
 

+ 0 - 1
app/src/main/res/layout/activity_sessions_intro.xml

@@ -14,7 +14,6 @@
         android:layout_height="match_parent"
         android:background="?android:attr/colorBackground"
         android:clipToPadding="false"
-        android:fillViewport="true"
         android:scrollbarAlwaysDrawVerticalTrack="true"
         app:layout_behavior="@string/appbar_scrolling_view_behavior">
 

+ 1 - 1
app/src/main/res/layout/fragment_link_new_device_verify.xml

@@ -69,7 +69,7 @@
 
         <com.google.android.material.button.MaterialButton
             android:id="@+id/no_match_button"
-            style="@style/Threema.MaterialButton.Action.Outline"
+            style="@style/Threema.MaterialButton.Action.Outline.Info"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/no_match_question" />

+ 2 - 1
app/src/main/res/layout/view_emoji_selection.xml

@@ -8,7 +8,8 @@
         android:layout_height="wrap_content"
         android:animateLayoutChanges="true"
         android:padding="16dp"
-        tools:background="?attr/colorPrimaryContainer"
+        android:background="?attr/colorSurfaceContainer"
+        tools:background="?attr/colorSurfaceContainer"
         tools:layout_gravity="center">
 
         <androidx.appcompat.widget.AppCompatImageView

+ 1 - 1
app/src/main/res/layout/work_intro_consumer_notice.xml

@@ -11,7 +11,7 @@
         android:layout_width="64dp"
         android:layout_height="64dp"
         android:importantForAccessibility="no"
-        android:src="@drawable/ic_app_icon_consumer"
+        android:src="@drawable/ic_app_icon_private"
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toTopOf="parent" />

+ 69 - 1
app/src/main/res/values-be-rBY/strings.xml

@@ -60,7 +60,9 @@
     <string name="prefs_vibrate">Вібрацыя</string>
     <string name="prefs_sum_vibrate">Вібрацыя пры ўваходным паведамленні</string>
     <!-- Label on checkbox in notification settings screen, to let the user enable/disable the use of the device's color LED for notifications. Only relevant on Android 6 and 7 -->
+    <string name="prefs_notification_light">Індыкатар апавяшчэнняў</string>
     <!-- Summary on checkbox in notification settings screen, to let the user enable/disable the use of the device's color LED for notifications. Only relevant on Android 6 and 7 -->
+    <string name="prefs_sum_notification_light">Выкарыстоўваць каляровы святлодыёд (калі даступны) для ўваходных паведамленняў</string>
     <string name="prefs_sum_light">Белы</string>
     <string name="prefs_title_wallpaper">Выбраць шпалеры</string>
     <string name="prefs_sum_wallpaper">Выберыце відарыс для фону</string>
@@ -99,6 +101,7 @@
     <string name="next">Далей</string>
     <string name="finish">Скончыць</string>
     <string name="please_wait">Пачакайце…</string>
+    <string name="please_wait_timeout">Гэта займае больш часу, чым чакалася</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="wizard_first_create_id">Стварэнне вашага ${app_name_short} ID…</string>
     <string name="wizard1_sync_contacts">Сінхранізацыя кантактаў…</string>
@@ -162,6 +165,7 @@
     <string name="delete_id_message">Калі ў вас няма створанай або экспартаванай рэзервовай копіі гэтага ID, вы больш ніколі не зможаце адпраўляць ці атрымліваць паведамленні, выкарыстоўваючы гэты ID.\n\nКалі вы больш не хочаце выкарыстоўваць гэты ID, рэкамендуецца задаць пароль водгуку і адклікаць ID на сайце  .ch/revoke перад яго выдаленнем.</string>
     <string name="delete_id_message2">Апошняе папярэджанне: вы сапраўды хочаце выдаліць свой ID?</string>
     <string name="delete_id_sum">Назаўжды выдаліць свой ID і ўсе даныя на гэтай прыладзе</string>
+    <string name="delete_all_data_prompt">Выдаліць усе даныя праграмы?</string>
     <string name="backup_password_summary">Ваш экспарт ID будзе зашыфраваны паролем. Выкарыстоўвайце спалучэнне лацінскіх літар, лічбаў і спецыяльных сімвалаў. Не забудзьцеся запісаць ці запомніць свой новы пароль!</string>
     <string name="backup_password_again_summary">Увядзіце пароль яшчэ раз</string>
     <string name="password_hint">Пароль</string>
@@ -200,6 +204,7 @@
     <string name="no_contacts"><![CDATA[У вас пакуль няма ніякіх кантактаў. Уключыце сінхранізацыю (Налады > Прыватнасць) або дадайце кантакты ўручную.]]></string>
     <!-- Empty state text for Contacts tab, shown when there are no contacts and Contact Synchronization is enabled -->
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="no_contacts_sync_on"><![CDATA[У вас пакуль няма кантактаў. Сінхранізацыя ўключана, але, здаецца, ніводзін з вашых кантактаў з адраснай кнігі не карыстаецца праграмай ${app_name_short} (запрасіце іх!).]]></string>
     <string name="masterkey_title">Увядзіце кодавую фразу</string>
     <string name="masterkey_body">Ваш галоўны ключ абаронены з дапамогай кодавай фразы.  Увядзіце кодавую фразу, каб разблакаваць ключ.</string>
     <string name="masterkey_unlocking">Разблакір. галоўнага ключа</string>
@@ -219,6 +224,7 @@
     <string name="threema_version">Версія</string>
     <string name="threema_version_code">Код версіі</string>
     <!-- Section title on "About" screen, for section which shows information about the (on prem) server and user credentials -->
+    <string name="about_server_config_title">Канфігурацыя сервера</string>
     <string name="wrong_backupid_or_password_or_no_internet_connection">Адсутнічае падлучэнне да Інтэрнэту, няправільныя даныя экспарту ID ці няправільны пароль</string>
     <string name="prefs_header_other">Іншае</string>
     <string name="an_error_occurred">Адбылася памылка</string>
@@ -240,16 +246,20 @@
     <string name="deleting_thread">Выдаленне чата</string>
     <string name="enter_serial_body"><![CDATA[Калі ласка, увядзіце ваш ліцэнзійны ключ ці націсніце тут, каб атрымаць яго: https://shop.threema.ch/retrieve_keys]]></string>
     <!-- ${app_name_short} is a placeholder for the app's name, it must be kept as-is, not translated. -->
+    <string name="work_enter_serial_body">Калі ласка, увядзіце ўліковыя дадзеныя ${app_name_short},  дазволеныя вашай кампаніяй.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="enter_serial_title">Разблакаваць ${app_name}</string>
     <!-- ${app_name} is a placeholder for the app's name, it must be kept as-is, not translated. -->
     <string name="serial_required_want_exit">Ліцэнзійны ключ з\'яўляецца несапраўдным. Вы хочаце паспрабаваць яшчэ раз ці выйсці з ${app_name}?</string>
     <!-- ${app_name} is a placeholder for the app's name, it must be kept as-is, not translated. -->
+    <string name="work_serial_required_want_exit">Ліцэнзія несапраўдная. Паспрабаваць яшчэ раз ці выйсці з ${app_name}?</string>
     <!-- Message shown on progress dialog that shows while checking whether the user has a valid license -->
     <string name="checking_serial">Праверка ліцэнзіі</string>
     <!-- Message shown on progress dialog that shows while the credentials that the user entered are being checked for their validity -->
+    <string name="work_checking_credentials">Праверка ўліковых дадзеных</string>
     <string name="update_available">Даступна абнаўленне</string>
     <!-- Message shown in Update dialog to inform the user that a new version of the app is available -->
+    <string name="update_available_message">Даступная новая версія. Хочаце спампаваць яе зараз?</string>
     <string name="no_update_available">Абнаўленняў няма</string>
     <string name="download">Спампаваць</string>
     <string name="not_now">Нагадайце мне пазней</string>
@@ -333,10 +343,15 @@
     <string name="state_dialog_edited">Адрэд.</string>
     <string name="state_dialog_deleted">Выдалена</string>
     <string name="state_dialog_status">Статус</string>
+    <string name="title_tab_recent">Нядаўнія</string>
     <string name="no_recent_conversations">Размовы не знойдзены</string>
     <string name="save_changes">Захаваць</string>
     <string name="creating_group">Стварэнне суполкі</string>
     <string name="updating_group">Абнаўленне суполкі</string>
+    <string name="leaving_group">Выхад з суполкі</string>
+    <string name="disbanding_group">Суполка, якая замыкаецца</string>
+    <string name="removing_group">Выдаленне суполкі</string>
+    <string name="resyncing_group">Паўторная сінхранізацыя суполкі </string>
     <string name="status_create_group">Суполка створана.</string>
     <string name="status_rename_group">Суполка пераназвана ў «%1$s»</string>
     <string name="status_group_new_photo">Суполка абноўлена.</string>
@@ -354,6 +369,7 @@
     <string name="synchronize_contact">Сінхр-я адраснай кнігі</string>
     <string name="exclude_contact">Выключыць з аўтаматычнай сінхран</string>
     <string name="prefs_header_lists">Спісы</string>
+    <string name="prefs_title_blocked_contacts">Заблакіраваныя кантакты</string>
     <string name="prefs_sum_blocked_contacts">Паведамленні ад пералічаных тут ID, будуць пра ігнараваны.</string>
     <string name="verified">Праверана</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
@@ -625,7 +641,9 @@
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="permission_contacts_required">Каб адпраўляць кантакты, дазвольце ${app_name} чытанне кантактаў.</string>
     <!-- "Thumbs up" should be translated by the name of the emoji 👍 -->
+    <string name="message_acknowledged">\"Падабайка\" адпраўлена</string>
     <!-- "Thumbs down" should be translated by the name of the emoji 👎 -->
+    <string name="message_declined">\"Не да спадобы\" адпраўлена</string>
     <string name="notifications_settings">Налады апавяшчэнняў</string>
     <string name="notifications_default">Прадвызначаны налады</string>
     <string name="notifications_until">Да% s</string>
@@ -641,6 +659,7 @@
     <string name="new_wizard_lets_get_started">Пачнём!</string>
     <string name="new_wizard_setup_threema">Наладзіць зараз</string>
     <!-- Label on call-to-action button in setup wizard when app is first opened, to allow the user to start setting up the app. ${app_name} is a placeholder for the app's name, it must be kept as-is, not translated. -->
+    <string name="work_new_wizard_setup_threema">Наладзьце ${app_name}</string>
     <string name="new_wizard_restore_id_backup">Аднавіць экспартаваны ID</string>
     <!-- ${app_name} is a placeholder for the app's name, it must be kept as-is, not translated. -->
     <string name="new_wizard_welcome">Сардэчна запрашаем у ${app_name}!</string>
@@ -723,6 +742,20 @@
     <string name="clone_group_message">Будзе створаны клон суполкі з вамі, у якасці адміністратара.  Працягнуць?</string>
     <string name="prefs_proximity_sensor">Ужываць датчык набліжэння</string>
     <string name="prefs_proximity_sensor_explain">Ужываць гутарковы дынамік для прайгравання галасавых паведамленняў, калі датчык набліжэння зачынены</string>
+    <string name="error_creating_group_network">Суполка не створана. Праверце падключэнне да Інтэрнэту і паспрабуйце яшчэ раз.</string>
+    <string name="error_creating_group_internal">З-за ўнутранай памылкі суполка не была створана. Паўтарыце спробу пазней.</string>
+    <string name="error_cloning_group_network">Суполка не была кланіравана. Праверце падключэнне да Інтэрнэту і паспрабуйце яшчэ раз.</string>
+    <string name="error_cloning_group_internal">З-за ўнутранай памылкі суполка не была кланіравана. Паўтарыце спробу пазней.</string>
+    <string name="error_updating_group_network">Не ўдалося ўжыць змены. Праверце падключэнне да Інтэрнэту і паспрабуйце яшчэ раз.</string>
+    <string name="error_updating_group_internal">З-за ўнутранай памылкі змены не маглі быць ужытыя. Паўтарыце спробу пазней.</string>
+    <string name="error_leaving_group_network">Суполка не пакінута. Праверце падключэнне да Інтэрнэту і паспрабуйце яшчэ раз.</string>
+    <string name="error_leaving_group_internal">З-за ўнутранай памылкі суполку не ўдалося пакінуць. Паўтарыце спробу пазней.</string>
+    <string name="error_disbanding_group_network">Суполка не была распушчана. Калі ласка, праверце падключэнне да Інтэрнэту і паспрабуйце яшчэ раз.</string>
+    <string name="error_disbanding_group_internal">З-за ўнутранай памылкі суполка не была распушчана. Паўтарыце спробу пазней.</string>
+    <string name="error_removing_group_network">Суполка не была выдалена. Праверце падключэнне да Інтэрнэту і паспрабуйце яшчэ раз.</string>
+    <string name="error_removing_group_internal">З-за ўнутранай памылкі суполка не была выдалена. Паўтарыце спробу пазней.</string>
+    <string name="error_resyncing_group_network">Суполка не была сінхранізавана паўторна. Праверце падключэнне да Інтэрнэту і паспрабуйце яшчэ раз.</string>
+    <string name="error_resyncing_group_internal">З-за ўнутранай памылкі суполка не была сінхранізавана паўторна. Паўтарыце спробу пазней.</string>
     <string name="no_media_found_generic">У гэтым чаце не знойдзена мультымедыя, якое адпавядае выбару.</string>
     <string name="max_images_reached">Макс.  %d элементаў можна рэдагаваць адначасова</string>
     <string name="enter_description">Калі ласка, апішыце памылку/праблему тут.</string>
@@ -754,6 +787,7 @@
     <string name="grace_thirty_minutes">30 хвілін</string>
     <string name="grace_never">Ніколі (уручную)</string>
     <string name="never">Ніколі</string>
+    <string name="access_protection_cannot_be_removed">Абарона доступу не можа быць знята, бо ёсць як мінімум адзін прыватны чат.</string>
     <string name="verification_started">Праверка пачалася</string>
     <string name="cannot_open_file">Немагчыма адкрыць файл</string>
     <string name="prefs_title_image_attach_previews">Хуткі выбар відарыса</string>
@@ -951,6 +985,7 @@
     <!-- ${company_name} is a placeholder for the name of the company that operates the app, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="safe_configure_server_explain">Можна выкарыстоўваць сэрвер ${app_name_short} Safe або паказаць пабочны сэрвер для рэзервовага капіявання.</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="onprem_safe_configure_server_explain">Захавайце рэзервовую копію ${app_name_short} на серверы вашай арганізацыі або пазначце іншы сервер рэзервовага капіравання.</string>
     <string name="safe_use_default_server">Прадвызначаны сервер</string>
     <string name="safe_test_server">Тэставы сервер</string>
     <string name="safe_advanced_options">Пашыраныя налады</string>
@@ -1105,6 +1140,7 @@
     <string name="to_archive">Архіў</string>
     <string name="archived_chats">Архіваваныя чаты</string>
     <!-- Menu option in context menu when long-pressing a chat in the Chats tab, allows the user to move the selected chat to the archive -->
+    <string name="archive_chat">Архіваваць чат</string>
     <string name="unarchive">Выняць</string>
     <string name="no_archived_chats">Няма архіваваных чатаў.\nКаб архіваваць чат, правядзіце па ім налева ў спісе паведамленняў</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
@@ -1124,6 +1160,8 @@
     <string name="continue_recording">Працягнуць запіс</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". %1$s is a placeholder for the version number. They must not be translated. -->
     <string name="whatsnew_title">Што новага ў ${app_name} %1$s?</string>
+    <string name="whatsnew_headline"><![CDATA[<p>Цяпер вы можаце падключыць сваю прыладу Android да новага прыкладання для ПК (бэта-версія) і пратэставаць функцыю працы з некалькімі прыладамі.</p>
+<p>Для атрымання дадатковай інфармацыі перайдзіце ў раздзел «Меню > Threema 2.0 для ПК (бэта-версія)».</p>]]></string>
     <string name="tap_to_start">Націсьніце тут, каб запусціць %s.</string>
     <string name="two_years">2 года</string>
     <string name="invalid_backup_path">Нядзейнічае.шлях да рэз.копіі</string>
@@ -1643,11 +1681,23 @@
     <!-- ${app_name_desktop} is a placeholder for the desktop app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <!-- The part of this text that is surrounded by the square brackets will be clickable by the user and lead them to the download page for the desktop client -->
     <!-- The text in [square brackets] must be translated, and the brackets must be kept around the translation. ${app_name_desktop} is a placeholder for the app's name and must NOT be translated -->
+    <string name="md_linked_devices_empty">Перад падключэннем новай прылады, калі ласка, запампуйце і адкрыйце апошнюю бэта-версію [${app_name_desktop} для камп\'ютара].</string>
     <string name="md_link_device_qr_scan_message">Калі ласка, адсканіруйце qr-код</string>
     <string name="directory_request_failed">Не ўдалося запытаць каталог.  Паспрабуй яшчэ.</string>
     <string name="add_shortcut_exists">Ярлык для гэтай мэты ўжо існуе.</string>
+    <string name="scan_qr_code">Сканіруйце QR-код</string>
     <!-- ${app_name_desktop} is a placeholder for the desktop app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="scan_qr_code_explain">Адсканіруйце QR-код, які адлюстроўваецца ў бэта-версіі ${app_name_desktop} для камп\'ютараў, на прыладзе, якую вы хочаце падключыць.</string>
+    <string name="connecting">Падключэнне…</string>
+    <string name="trust_new_device">Давяраць новай прыладзе</string>
+    <string name="trust_new_device_explain">Выберыце тыя ж малюнкі, што паказаны на новай прыладзе, каб пацвердзіць, што вы ёй давяраеце.</string>
+    <string name="trust_new_device_info">Новая прылада будзе захоўваць незалежную копію вашага профілю %s, і паведамленні будуць адпраўляцца і атрымліваць ад вашага імя.</string>
+    <string name="no_match_question">Няма супадзення?</string>
+    <string name="sending_data">Адпраўка дадзеных…</string>
+    <string name="continue_on_new_device">Калі ласка, працягвайце на новай прыладзе</string>
+    <string name="device_linked_successfully">Прылада паспяхова падключана</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="device_linked_successfully_explain">Цяпер праграмай ${app_name} можна карыстацца на прыладзе, якую вы толькі што падключылі (нават калі гэтая прылада выключана або не падключана да Інтэрнэту).</string>
     <string name="resend_message_dialog_title">Паўторна адправіць  паведамленне?</string>
     <string name="resend_message_dialog_message">Гэта паведамленне не можа быць адпраўлена ўсім удзельнікам.  Паўторна адправіць паведамленне %1$s?</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
@@ -1667,7 +1717,9 @@
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="problemsolver_explain_app_battery_usgae_optimized">Праграме не дазваляецца падтрымліваць пастаяннае злучэнне з серверамі, якое патрабуецца для працы ${app_name_short} Push.  Вы не будзеце атрымліваць інфармацыю аб новых паведамленнях, калі праграма працуе ў фонавым рэжыме.  Каб выправіць гэта, націсніце «Выкарыстанне батарэі праграмы» і выберыце «Без абмежаванняў».</string>
     <!-- Title of warning message that informs the user that their app is no longer supported. -->
+    <string name="problemsolver_title_android_version_retired">Гэта праграма больш не абнаўляецца</string>
     <!-- Details of warning message that informs the user that their app is no longer supported. -->
+    <string name="problemsolver_explain_android_version_retired">Вы карыстаецеся састарэлай версіяй Android, якая больш не падтрымліваецца Threema з меркаванняў бяспекі. Гэта азначае, што вы больш не будзеце атрымліваць абнаўленні для праграмы Threema. Каб працягваць карыстацца Threema з усімі яе функцыямі, абнавіце аперацыйную сістэму да сучаснай версіі.</string>
     <string name="problemsolver_to_settings">Да налад</string>
     <string name="prefs_advanced_options">Дадатковыя параметры</string>
     <string name="push_service">Паслуга Push</string>
@@ -1685,7 +1737,8 @@
     <string name="new_group_messages">Новыя групавыя паведамленні</string>
     <string name="individual_notification_settings">Індывідуальныя налады апавяшчэнняў</string>
     <string name="delete_message_not_supported_for_all_group_members">Гэта паведамленне не будзе выдалена для наступных удзельнікаў групы: %1$s</string>
-    <string name="work_intro_more_link_text">Даведайцеся больш аб Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Даведайцеся больш пра ${app_name}</string>
     <string name="work_intro_subtitle">Бяспечны бізнес-месенджэр\nдля кампаній.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Уваход ${app_name}</string>
@@ -1697,6 +1750,11 @@
     <string name="incoming_calls">Уваходны званкі</string>
     <string name="group_chats">Суполкі</string>
     <string name="edit_history_file_no_caption">Без подпісу</string>
+    <string name="device_linking_failed">Памылка падключэння прылады</string>
+    <string name="device_linking_failed_explain">Не ўдалося падключыць прыладу. Паспрабуйце яшчэ раз.\nПрычына: %s.</string>
+    <string name="qr_code_scan_error">Падчас сканавання QR-кода адбылася памылка</string>
+    <string name="verification_failed">Праверка не ўдалася</string>
+    <string name="md_device_currently_active">Цяпер актыўны</string>
     <string name="device_linking_cancel_dialog_continue">Працягнуць</string>
     <string name="md_drop_device_dialog_close_button">Закрыць</string>
     <string name="md_drop_device_failed_dialog_button_close">Закрыць</string>
@@ -1724,12 +1782,22 @@
     <!-- The part of this text that is surrounded by the square brackets will be clickable by the user and lead them to the download page for the desktop client -->
     <!-- The text in [square brackets] must be translated, and the brackets must be kept around the translation. -->
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="device_linking_error_invalid_contact_title">Няправільны кантакт</string>
+    <string name="device_linking_error_invalid_contact_body">Кантакт з ідэнтыфікацыйным нумарам %1$s няправільна захаваны на гэтай прыладзе і перашкаджае падключэнню новай прылады. Звярніцеся ў службу падтрымкі («Галоўнае меню > Даведка»).</string>
     <string name="device_linking_error_screen_close">Закрыць</string>
+    <string name="work_directory_title">Даведнік кампаній</string>
     <!-- Instruction text for the user directory search -->
+    <string name="work_directory_search">Пошук у каталогу</string>
     <!-- Prompt to the user shown in the work directory search. ${app_name_short} is a placeholder for the app's name, it must be kept as-is, not translated. -->
+    <string name="work_directory_empty_view_text">Калі ласка, увядзіце як мінімум 3 сімвалы імя, каб пачаць пошук у каталогу карыстальнікаў ${app_name_short} вашай кампаніі.</string>
     <!-- Message that is shown when the user wants to share an invalid file. -->
+    <string name="invalid_file_cannot_be_shared">Гэты файл несапраўдны і не можа быць абагулены</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
+    <string name="contact_availability_status_available">Даступна</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <string name="contact_availability_status_unavailable">Недаступна</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
     <plurals name="contacts_counter_label">
         <item quantity="one">%d кантакт</item>
         <item quantity="few">%d кантакты</item>

+ 36 - 3
app/src/main/res/values-bg/strings.xml

@@ -101,6 +101,7 @@
     <string name="next">Следващо</string>
     <string name="finish">Край</string>
     <string name="please_wait">Моля, изчакайте…</string>
+    <string name="please_wait_timeout">Това отнема повече време от очакваното</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="wizard_first_create_id">Създайте своя ${app_name_short} идентификатор…</string>
     <string name="wizard1_sync_contacts">Синхронизирайте контактите…</string>
@@ -164,6 +165,7 @@
     <string name="delete_id_message">Освен ако не сте създали резервно копие или експортирали/копирали този идентификатор, Вие никога няма да можете да изпращате или получавате         съобщения с този идентификатор отново.\n\nАко не искате да използвате този идентификатор повече, се препоръчва да създадете парола за анулиране и да анулирате идентификатора на myid.threema.ch/revoke преди да го изтриете.</string>
     <string name="delete_id_message2">Последно предупреждение: наистина ли искате да изтриете идентификатора на това устройство?</string>
     <string name="delete_id_sum">Окончателно изтриване на ${app_name_short} идентификатора и всички чатове на това устройство</string>
+    <string name="delete_all_data_prompt">Искате ли да изтриете всички данни на приложението?</string>
     <string name="backup_password_summary">Вашият експортиран идентификатор ще бъде криптиран с парола. Използвайте комбинация от букви, цифри и символи. Не забравяйте какво е въведено тук!</string>
     <string name="backup_password_again_summary">Въведете паролата отново</string>
     <string name="password_hint">Парола</string>
@@ -346,6 +348,10 @@
     <string name="save_changes">Запазете</string>
     <string name="creating_group">Създаване на групата</string>
     <string name="updating_group">Обновяване на групата</string>
+    <string name="leaving_group">Напускане на групата</string>
+    <string name="disbanding_group">Разпускане на групата</string>
+    <string name="removing_group">Изтриване на групата</string>
+    <string name="resyncing_group">Повторна синхронизация на групата</string>
     <string name="status_create_group">Групата е създадена.</string>
     <string name="status_rename_group">Групата е преименувана на „%1$s“</string>
     <string name="status_group_new_photo">Снимката на групата е обновена.</string>
@@ -700,7 +706,7 @@
     <string name="new_wizard_info_link">Предоставяйки ни Вашия телефонен номер и имейл, ${app_name_short} може да помогне на приятелите да Ви намират автоматично, ако Ви имат като контакт в техните списъци с контакти. Данните Ви ще бъдат запазени в едностранно криптирана (хеш) форма на нашите сървъри. Може просто да прескочите тази стъпка, ако искате да ползвате ${app_name} напълно анонимно.</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="new_wizard_info_link_phone_only">Предоставяйки ни Вашия телефонен номер, ${app_name_short} може да помогне на приятелите да
-         Ви намират автоматично, ако Ви имат като контакт в техните списъци с контакти. Номерът Ви ще бъде запазен в 
+         Ви намират автоматично, ако Ви имат като контакт в техните списъци с контакти. Номерът Ви ще бъде запазен в
         едностранно криптирана (хеш) форма на нашите сървъри. Може просто да прескочите тази стъпка, ако искате да ползвате ${app_name_short}
       напълно анонимно.</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
@@ -745,6 +751,20 @@
     <string name="clone_group_message">Това действие ще създаде копие на групата с Вас като администратор. Ще продължите ли?</string>
     <string name="prefs_proximity_sensor">Използване на сензора за близост</string>
     <string name="prefs_proximity_sensor_explain">Използване на слушалка за възпроизвеждане на гласови съобщения, ако сензорът за близост е закрит</string>
+    <string name="error_creating_group_network">Групата не бе създадена. Моля, проверете Вашата интернет връзка и опитайте отново.</string>
+    <string name="error_creating_group_internal">Поради вътрешна грешка групата не бе създадена. Моля, опитайте отново по-късно.</string>
+    <string name="error_cloning_group_network">Групата не бе клонирана. Моля, проверете Вашата интернет връзка и опитайте отново.</string>
+    <string name="error_cloning_group_internal">Поради вътрешна грешка, групата не бе клонирана. Моля, опитайте отново по-късно.</string>
+    <string name="error_updating_group_network">Промените не могат да бъдат приложени. Моля, проверете Вашата интернет връзка и опитайте отново.</string>
+    <string name="error_updating_group_internal">Поради вътрешна грешка промените не са приложени. Моля, опитайте отново по-късно.</string>
+    <string name="error_leaving_group_network">Групата не е напусната. Моля, проверете Вашата интернет връзка и опитайте отново.</string>
+    <string name="error_leaving_group_internal">Поради вътрешна грешка групата не е напусната. Моля, опитайте отново по-късно.</string>
+    <string name="error_disbanding_group_network">Групата не е разпусната. Моля, проверете Вашата интернет връзка и опитайте отново.</string>
+    <string name="error_disbanding_group_internal">Поради вътрешна грешка групата не е разпусната. Моля, опитайте отново по-късно.</string>
+    <string name="error_removing_group_network">Групата не е изтрита. Моля, проверете Вашата интернет връзка и опитайте отново.</string>
+    <string name="error_removing_group_internal">Поради вътрешна грешка групата не е изтрита. Моля, опитайте отново по-късно.</string>
+    <string name="error_resyncing_group_network">Групата не е повторно синхронизирана. Моля, проверете Вашата интернет връзка и опитайте отново.</string>
+    <string name="error_resyncing_group_internal">Поради вътрешна грешка групата не е повторно синхронизирана. Моля, опитайте отново по-късно.</string>
     <string name="no_media_found_generic">Няма мултимедийни елементи в този чат, които да съвпадат с избора Ви.</string>
     <string name="max_images_reached">Максимум %d елемента могат да се редактират едновременно</string>
     <string name="enter_description">Моля, опишете грешката/проблема тук.</string>
@@ -1563,7 +1583,7 @@
     <string name="prefs_summary_hibernation_api">За да предотвратите приложението ${app_name} да бъде поставено на пауза от системата след дълга неактивност, деактивирайте системната настройка „Поставете на пауза приложението, ако не се използва“.</string>
     <string name="unable_to_fetch_configuration">Няма достъп до данните от сървъра за настройки. Опитайте отново по-късно.</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
-    <string name="rogue_device_warning"><![CDATA[Засечена е връзка от друго устройство със същия ${app_name_short} идентификатор. Наскоро да сте използвали Вашия ${app_name_short} идентификатор от друго устройство? <br><br> Ако сте го направил\а, може да игнорирате това съобщение. <br><br> Ако не сте, поверителният Ви ключ може да е компрометиран. Моля, <a href=https://threema.com/faq/another_connection"> последвайте нашите предложения,</a> за да защитите Вашето устройство и Вашите данни преди да създадете нов идентификатор.]]></string>
+    <string name="rogue_device_warning"><![CDATA[Засечена е връзка от друго устройство със същия ${app_name_short} идентификатор. Наскоро да сте използвали Вашия ${app_name_short} идентификатор от друго устройство? <br><br> Ако сте го направил\а, може да игнорирате това съобщение. <br><br> Ако не сте, поверителният Ви ключ може да е компрометиран. Моля, <a href="https://threema.com/faq/another_connection"> последвайте нашите предложения,</a> за да защитите Вашето устройство и Вашите данни преди да създадете нов идентификатор.]]></string>
     <string name="fetch2_failure">Синхронизацията със сървъра за предоставяне на услуги е неуспешна.</string>
     <string name="no_members_support_group_calls">Няма повече членове в тази група, които да могат да отговорят на групови обаждания</string>
     <string name="group_calls">Групови обаждания</string>
@@ -1703,7 +1723,9 @@
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="problemsolver_explain_app_battery_usgae_optimized">На приложението не му е разрешено да поддържа постоянна връзка със сървърите, а това е необходимо на ${app_name_short} Push, за да работи. Вие няма да бъдете информирани за нови съобщения, когато приложението е във фонов режим. За да го поправите, натиснете на „Използване на батерията“ и изберете „Неограничено“.</string>
     <!-- Title of warning message that informs the user that their app is no longer supported. -->
+    <string name="problemsolver_title_android_version_retired">Това приложение вече не е актуално</string>
     <!-- Details of warning message that informs the user that their app is no longer supported. -->
+    <string name="problemsolver_explain_android_version_retired">Използвате остаряла версия на Андроид, която вече не се поддържа от Threema поради причини свързани със сигурността. Това означава, че няма да получавате актуализации на Threema. За да продължите да използвате Threema и всички негови функции, трябва да надградите/ъпгрейднете операционната система.</string>
     <string name="problemsolver_to_settings">Към настройките</string>
     <string name="prefs_advanced_options">Разширени опции</string>
     <string name="push_service">Push услуга</string>
@@ -1721,7 +1743,8 @@
     <string name="new_group_messages">Нови групови съобщения</string>
     <string name="individual_notification_settings">Индивидуални настройки на известията</string>
     <string name="delete_message_not_supported_for_all_group_members">Съобщението няма да бъде изтрито за следните членове на групата: %1$s</string>
-    <string name="work_intro_more_link_text">Научете повече за Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Научете повече ${app_name}</string>
     <string name="work_intro_subtitle">Сигурният бизнес месинджър\nза фирми.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Вписване в ${app_name}</string>
@@ -1751,6 +1774,7 @@
     <string name="device_linking_cancel_dialog_continue">Продължете</string>
     <string name="md_drop_device_dialog_drop_button">Премахнете устройство</string>
     <string name="md_drop_device_dialog_close_button">Затворете</string>
+    <string name="md_drop_device_failed_dialog_title">Премахването на свързаните устройства може да е неуспешно</string>
     <string name="md_drop_device_failed_dialog_message">Моля, проверете интернет връзката Ви и опитайте отново.</string>
     <string name="md_drop_device_failed_dialog_button_close">Затворете</string>
     <!-- accessibility -->
@@ -1812,6 +1836,8 @@
     <string name="device_linking_error_emoji_mismatch_body">Изглежда, че има проблем с връзката към новото устройство. Моля, рестартирайте приложението на новото устройство и опитайте отново.</string>
     <string name="device_linking_error_unexpected_title">Неочаквана грешка</string>
     <string name="device_linking_error_unexpected_body">Моля, опитайте се да свържете устройството отново. Ако проблемът продължава, свържете се с екипа по поддръжка (Основно меню &gt; Помощ).</string>
+    <string name="device_linking_error_invalid_contact_title">Невалиден контакт</string>
+    <string name="device_linking_error_invalid_contact_body">Контактът %1$s е запазен неправилно на това устройство и пречи на свързването с новото устройство. Моля, свържете се с поддръжката (\"Основно меню &gt; Помощ\").</string>
     <string name="device_linking_error_screen_close">Затворете</string>
     <string name="work_directory_title">Директория на фирмата</string>
     <!-- Instruction text for the user directory search -->
@@ -1819,8 +1845,15 @@
     <!-- Prompt to the user shown in the work directory search. ${app_name_short} is a placeholder for the app's name, it must be kept as-is, not translated. -->
     <string name="work_directory_empty_view_text">Моля, въведете поне 3 букви от името, за да започне търсенето във фирмената директория с ${app_name_short} потребители.</string>
     <!-- Message that is shown when the user wants to share an invalid file. -->
+    <string name="invalid_file_cannot_be_shared">Този файл е невалиден и не може да бъде споделен</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
+    <string name="contact_availability_status_available">Достъпен</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <string name="contact_availability_status_unavailable">Недостъпен</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">Предоставеният адрес на сървъра е невалиден. Моля, свържете се с Вашия администратор.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Предоставеният линк за активация е невалиден. Моля, свържете се с Вашия администратор.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d контакт</item>
         <item quantity="other">%d контакти</item>

+ 3 - 0
app/src/main/res/values-ca/strings.xml

@@ -1445,6 +1445,7 @@ Si esteu canviant a un dispositiu nou, desinstal·leu o desactiveu %s al disposi
     <!-- Title of warning message that informs the user that their app is no longer supported. -->
     <!-- Details of warning message that informs the user that their app is no longer supported. -->
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <!-- accessibility -->
     <!-- Hint shown on message details screen, to let the user know how they can view a message's emoji reactions -->
     <!-- Title shown in popup above emoji reaction buttons on a message, to hint to the user that they can long-press to view the details -->
@@ -1464,6 +1465,8 @@ Si esteu canviant a un dispositiu nou, desinstal·leu o desactiveu %s al disposi
     <!-- Message that is shown when the user wants to share an invalid file. -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contacte</item>
         <item quantity="other">%d contactes</item>

+ 6 - 1
app/src/main/res/values-cs/strings.xml

@@ -1737,7 +1737,8 @@ přátelům vás automaticky najít, pokud vás mají v adresáři svého telef
     <string name="new_group_messages">Nové skupinové zprávy</string>
     <string name="individual_notification_settings">Individuální nastavení oznámení</string>
     <string name="delete_message_not_supported_for_all_group_members">Zpráva nebude odstraněna pro následující členy skupiny: %1$s</string>
-    <string name="work_intro_more_link_text">Zjistěte více o Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Zjistěte více o aplikaci ${app_name}</string>
     <string name="work_intro_subtitle">Bezpečný messenger pro firmy.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Přihlášení ${app_name}</string>
@@ -1845,6 +1846,10 @@ přátelům vás automaticky najít, pokud vás mají v adresáři svého telef
     <string name="contact_availability_status_available">Dostupný</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Nedostupný</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">Poskytnutá URL serveru je neplatná. Kontaktujte prosím svého administrátora.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Aktivační odkaz je neplatný. Kontaktujte prosím svého administrátora.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d kontakt</item>
         <item quantity="few">%d kontakty</item>

+ 8 - 1
app/src/main/res/values-de/strings.xml

@@ -1767,7 +1767,8 @@ sicheren Ort gesichert oder ausgedruckt haben.</string>
     <string name="new_group_messages">Neue Gruppen-Nachrichten</string>
     <string name="individual_notification_settings">Individuelle Benachrichtigungs-Einstellungen</string>
     <string name="delete_message_not_supported_for_all_group_members">Bei folgenden Gruppenmitgliedern wird die Nachricht nicht gelöscht: %1$s</string>
-    <string name="work_intro_more_link_text">Mehr über Threema Work erfahren</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Mehr über ${app_name} erfahren</string>
     <string name="work_intro_subtitle">Der sichere Business-Messenger\nfür Unternehmen.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Anmeldung ${app_name}</string>
@@ -1870,7 +1871,13 @@ sicheren Ort gesichert oder ausgedruckt haben.</string>
     <!-- Message that is shown when the user wants to share an invalid file. -->
     <string name="invalid_file_cannot_be_shared">Diese Datei ist ungültig und kann nicht geteilt werden</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
+    <string name="contact_availability_status_available">Verfügbar</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <string name="contact_availability_status_unavailable">Beschäftigt</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">Die Server-URL ist ungültig. Bitte kontaktieren Sie Ihren Administrator.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Der Aktivierungslink ist ungültig. Bitte kontaktieren Sie Ihren Administrator.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d Kontakt</item>
         <item quantity="other">%d Kontakte</item>

+ 6 - 1
app/src/main/res/values-es/strings.xml

@@ -1744,7 +1744,8 @@ almacenado.</string>
     <string name="new_group_messages">Mensajes grupales nuevos</string>
     <string name="individual_notification_settings">Configuración de notificaciones individuales</string>
     <string name="delete_message_not_supported_for_all_group_members">El mensaje no se eliminará para los siguientes miembros del grupo: %1$s</string>
-    <string name="work_intro_more_link_text">Obtener más información sobre Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Obtenga más información sobre ${app_name}</string>
     <string name="work_intro_subtitle">El mensajero empresarial seguro\npara empresas.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Iniciar sesión ${app_name}</string>
@@ -1850,6 +1851,10 @@ almacenado.</string>
     <string name="contact_availability_status_available">Disponible</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">No disponible</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">La URL del servidor facilitada no es válida. Póngase en contacto con su administrador.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">El enlace de activación no es válido. Póngase en contacto con su administrador.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contacto</item>
         <item quantity="other">%d contactos</item>

+ 6 - 1
app/src/main/res/values-fr/strings.xml

@@ -1737,7 +1737,8 @@ Veuillez saisir une question pour votre enquête.</string>
     <string name="new_group_messages">Nouveaux messages de groupe</string>
     <string name="individual_notification_settings">Paramètres de notification individuels</string>
     <string name="delete_message_not_supported_for_all_group_members">Le message ne sera pas supprimé pour les membres suivants du groupe : %1$s</string>
-    <string name="work_intro_more_link_text">En savoir plus sur Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">En savoir plus sur ${app_name}</string>
     <string name="work_intro_subtitle">La messagerie instantanée sécurisée\npour les entreprises.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Connecter ${app_name}</string>
@@ -1843,6 +1844,10 @@ Veuillez saisir une question pour votre enquête.</string>
     <string name="contact_availability_status_available">Disponible</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Indisponible</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">L’adresse URL du serveur fournie n’est pas valide. Veuillez contacter votre administrateur.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Le lien d’activation n’est pas valide. Veuillez contacter votre administrateur.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contact</item>
         <item quantity="other">%d contacts</item>

+ 6 - 1
app/src/main/res/values-gsw/strings.xml

@@ -1731,7 +1731,8 @@
     <string name="new_group_messages">Neui Gruppe-Nachrichte</string>
     <string name="individual_notification_settings">Individuelli Benachrichtigungsiistellige</string>
     <string name="delete_message_not_supported_for_all_group_members">Bi folgende Gruppemitglieder wird d’Nachricht nöd glöscht: %1$s</string>
-    <string name="work_intro_more_link_text">Meh über Threema Work erfahre</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Meh über ${app_name} erfahre</string>
     <string name="work_intro_subtitle">De sicheri Business-Messenger\nfür Undernehme.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Aamäldig ${app_name}</string>
@@ -1837,6 +1838,10 @@
     <string name="contact_availability_status_available">Verfüegbar</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Nöd verfüegbar</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">D’Server-URL isch ungültig. Bitte kontaktiered Sie Ihre Administrator.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">De Aktivierigslink isch ungültig. Bitte kontaktiered Sie Ihre Administrator.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d Kontakt</item>
         <item quantity="other">%d Kontäkt</item>

+ 3 - 0
app/src/main/res/values-hu/strings.xml

@@ -1455,6 +1455,7 @@ Ha új eszközre vált, kérjük, távolítsa el vagy deaktiválja a %s-t a rég
     <!-- Title of warning message that informs the user that their app is no longer supported. -->
     <!-- Details of warning message that informs the user that their app is no longer supported. -->
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <!-- accessibility -->
     <!-- Hint shown on message details screen, to let the user know how they can view a message's emoji reactions -->
     <!-- Title shown in popup above emoji reaction buttons on a message, to hint to the user that they can long-press to view the details -->
@@ -1474,6 +1475,8 @@ Ha új eszközre vált, kérjük, távolítsa el vagy deaktiválja a %s-t a rég
     <!-- Message that is shown when the user wants to share an invalid file. -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
     <plurals name="contacts_counter_label">
         <item quantity="one">%d névjegyek</item>
         <item quantity="other">%d névjegyek</item>

+ 6 - 1
app/src/main/res/values-it/strings.xml

@@ -1754,7 +1754,8 @@ automaticamente in caso di inattività dopo un intervallo predefinito (solo cara
     <string name="new_group_messages">Nuovi messaggi di gruppo</string>
     <string name="individual_notification_settings">Impostazioni di notifica individuali</string>
     <string name="delete_message_not_supported_for_all_group_members">Il messaggio non verrà eliminato per i seguenti membri del gruppo: %1$s</string>
-    <string name="work_intro_more_link_text">Maggiori informazioni su Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Scopri di più su ${app_name}</string>
     <string name="work_intro_subtitle">L\'app di messaggistica sicura per le imprese.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Accedi ${app_name}</string>
@@ -1860,6 +1861,10 @@ automaticamente in caso di inattività dopo un intervallo predefinito (solo cara
     <string name="contact_availability_status_available">Disponibile</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Non disponibile</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">L\'URL del server fornito non è valido. Contatta l\'amministratore.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Il link di attivazione non è valido. Contatta l\'amministratore.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contatto</item>
         <item quantity="other">%d contatti</item>

+ 3 - 0
app/src/main/res/values-ja/strings.xml

@@ -1673,6 +1673,7 @@ https://myid.threema.ch/revoke に入力することで ID を削除すること
     <string name="unsupported_image_type">サポート外の画像形式: %s</string>
     <string name="add_contact_failed">連絡先の追加が失敗しました</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <!-- accessibility -->
     <!-- Hint shown on message details screen, to let the user know how they can view a message's emoji reactions -->
     <!-- Title shown in popup above emoji reaction buttons on a message, to hint to the user that they can long-press to view the details -->
@@ -1692,6 +1693,8 @@ https://myid.threema.ch/revoke に入力することで ID を削除すること
     <!-- Message that is shown when the user wants to share an invalid file. -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
     <plurals name="contacts_counter_label">
         <item quantity="other">%d 連絡先</item>
     </plurals>

+ 6 - 1
app/src/main/res/values-nl-rNL/strings.xml

@@ -1737,7 +1737,8 @@ Voer een vraag in voor uw poll.</string>
     <string name="new_group_messages">Nieuwe groepsberichten</string>
     <string name="individual_notification_settings">Individuele meldingsinstellingen</string>
     <string name="delete_message_not_supported_for_all_group_members">Het bericht wordt niet verwijderd voor de volgende groepsleden: %1$s</string>
-    <string name="work_intro_more_link_text">Kom meer te weten over Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Meer informatie over ${app_name}</string>
     <string name="work_intro_subtitle">De veilige zakelijke messenger \nvoor bedrijven.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Inloggen bij ${app_name}</string>
@@ -1843,6 +1844,10 @@ Voer een vraag in voor uw poll.</string>
     <string name="contact_availability_status_available">Beschikbaar</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Niet beschikbaar</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">De opgegeven server-URL is ongeldig. Neem contact op met uw beheerder.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">De activatielink is ongeldig. Neem contact op met uw beheerder.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contactpersoon</item>
         <item quantity="other">%d contactpersonen</item>

+ 3 - 0
app/src/main/res/values-no/strings.xml

@@ -1651,6 +1651,7 @@ Om du bytter til en ny enhet, vennligst avinstaller eller deaktiver %s på den g
     <string name="unsupported_image_type">Ustøttet bildeformat: %s</string>
     <string name="application_setup_steps_failed">Det er krav om en aktiv internettforbindelse for å sjekke tilstanden til kontaktene dine. Sørg for at du er tilkoblet internett, og prøv igjen.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <!-- accessibility -->
     <!-- Hint shown on message details screen, to let the user know how they can view a message's emoji reactions -->
     <!-- Title shown in popup above emoji reaction buttons on a message, to hint to the user that they can long-press to view the details -->
@@ -1670,6 +1671,8 @@ Om du bytter til en ny enhet, vennligst avinstaller eller deaktiver %s på den g
     <!-- Message that is shown when the user wants to share an invalid file. -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
     <plurals name="contacts_counter_label">
         <item quantity="one">%d kontakt</item>
         <item quantity="other">%d kontakter</item>

+ 6 - 1
app/src/main/res/values-pl/strings.xml

@@ -1746,7 +1746,8 @@ podanie wyłącznie imienia lub pseudonimu. Jeśli nie ustawisz pseudonimu, będ
     <string name="new_group_messages">Nowe wiadomości grupowe</string>
     <string name="individual_notification_settings">Oddzielne ustawienia dotyczące powiadomień</string>
     <string name="delete_message_not_supported_for_all_group_members">Wiadomość nie zostanie usunięta w przypadku członków tej grupy: %1$s</string>
-    <string name="work_intro_more_link_text">Dowiedz się więcej o Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Dowiedz się więcej o aplikacji ${app_name}</string>
     <string name="work_intro_subtitle">Bezpieczny komunikator biznesowy\ndla firm.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Zaloguj się ${app_name}</string>
@@ -1854,6 +1855,10 @@ podanie wyłącznie imienia lub pseudonimu. Jeśli nie ustawisz pseudonimu, będ
     <string name="contact_availability_status_available">Dostępny(-a)</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Niedostępny(-a)</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">Podany adres URL serwera jest nieprawidłowy. Prosimy skontaktować się z administratorem.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Link aktywacyjny jest nieprawidłowy. Prosimy skontaktować się z administratorem.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d kontakt</item>
         <item quantity="few">%d kontakty</item>

+ 6 - 1
app/src/main/res/values-pt-rBR/strings.xml

@@ -1738,7 +1738,8 @@ Por favor, insira uma pergunta para a sua enquete.</string>
     <string name="new_group_messages">Novas mensagens de grupo</string>
     <string name="individual_notification_settings">Configurações de notificação individual</string>
     <string name="delete_message_not_supported_for_all_group_members">A mensagem não será excluída para os seguintes membros do grupo: %1$s</string>
-    <string name="work_intro_more_link_text">Saiba mais sobre o Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Saiba mais sobre ${app_name}</string>
     <string name="work_intro_subtitle">O messenger comercial seguro \npara empresas.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Fazer login ${app_name}</string>
@@ -1844,6 +1845,10 @@ Por favor, insira uma pergunta para a sua enquete.</string>
     <string name="contact_availability_status_available">Disponível</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Indisponível</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">O URL do servidor fornecido é inválido. Entre em contato com o seu administrador.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">O link de ativação é inválido. Entre em contato com o seu administrador.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contato</item>
         <item quantity="other">%d contatos</item>

+ 8 - 3
app/src/main/res/values-ru/strings.xml

@@ -165,7 +165,7 @@
     <string name="delete_id_message">Если у вас нет созданной или экспортированной резервной копии этого ID, вы больше никогда не сможете отправлять или получать сообщения, используя этот ID.\n\nЕсли вы больше не хотите использовать этот ID, рекомендуется задать пароль аннулирования и отозвать ID на сайте myid.threema.ch/revoke перед его удалением.</string>
     <string name="delete_id_message2">Последнее предупреждение: вы действительно хотите удалить свой ID?</string>
     <string name="delete_id_sum">Навсегда удалить свой ID и все данные на этом устройстве</string>
-    <string name="delete_all_data_prompt">Удалить все данные?</string>
+    <string name="delete_all_data_prompt">Удалить все данные приложения?</string>
     <string name="backup_password_summary">Ваш экспорт ID будет зашифрован паролем. Используйте сочетание латинских букв, цифр и специальных символов. Не забудьте записать или запомнить свой новый пароль!</string>
     <string name="backup_password_again_summary">Введите пароль ещё раз</string>
     <string name="password_hint">Пароль</string>
@@ -975,7 +975,7 @@
     <string name="disable_powermanager_title">Ограничения по питанию</string>
     <string name="disable_autostart_title">Автозапуск</string>
     <string name="unchanged">без изменений</string>
-    <string name="safe_learn_more_button">Узнайте больше</string>
+    <string name="safe_learn_more_button">Узнать больше</string>
     <string name="safe_enable_explain">Всё, что вам нужно для общения, хранится на вашем устройстве. У нас нет вашей учётной записи и мы не сможем помочь вам, если вы потеряете телефон или случайно удалите данные.\n\n${app_name_short} Safe создаёт автоматические резервные копии всех важных данных, в том числе ваших ключей, вашего списка контактов и групп (но не содержимого сообщений). Данные в анонимном виде хранятся на выбранном вами защищённом сервере.</string>
     <!-- ${app_name_short} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="safe_disable_confirm">Продолжить без включения ${app_name_short} Safe? При использовании ${app_name_short} Safe вы сможете восстановить ${app_name_short} ID, контакты и группы в случае потери доступа к устройству.</string>
@@ -1735,7 +1735,8 @@
     <string name="new_group_messages">Новые групповые сообщения</string>
     <string name="individual_notification_settings">Индивидуальные настройки уведомлений</string>
     <string name="delete_message_not_supported_for_all_group_members">Сообщение не будет удалено для следующих участников группы:%1$s</string>
-    <string name="work_intro_more_link_text">Подробнее о Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Подробнее о ${app_name}</string>
     <string name="work_intro_subtitle">Безопасный бизнес-мессенджер\nдля компаний.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Войти ${app_name}</string>
@@ -1843,6 +1844,10 @@
     <string name="contact_availability_status_available">Доступен</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Недоступен</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">Указанный URL сервера неправильный. Обратитесь к администратору.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Ссылка активации неправильная. Обратитесь к администратору.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d контакт</item>
         <item quantity="few">%d контакта</item>

+ 3 - 1
app/src/main/res/values-sk/strings.xml

@@ -1699,7 +1699,7 @@ Vykonajte prosím zálohú vašich údajov vhodnou metódou.</string>
     <string name="individual_notification_settings">Individuálne nastavenia oznámení</string>
     <string name="delete_message_not_supported_for_all_group_members">Správa nebude odstránená pre nasledujúcich členov skupiny:
 %1$s</string>
-    <string name="work_intro_more_link_text">Zistiť viac o Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_subtitle">Bezpečný messenger\npre firmy.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Prihlásenie ${app_name}</string>
@@ -1744,6 +1744,8 @@ Vykonajte prosím zálohú vašich údajov vhodnou metódou.</string>
     <!-- Message that is shown when the user wants to share an invalid file. -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile. Indicating that the person is currently available, i.e., not busy and not out-of-office -->
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
     <plurals name="contacts_counter_label">
         <item quantity="one">%d kontakt</item>
         <item quantity="few">%d kontakty</item>

+ 6 - 1
app/src/main/res/values-tr/strings.xml

@@ -1733,7 +1733,8 @@ sunucularımıza güvenli bir şekilde iletildi. Kişisel anahtar hiçbir zaman
     <string name="new_group_messages">Yeni Grup Mesajı</string>
     <string name="individual_notification_settings">Bireysel bildirim ayarları</string>
     <string name="delete_message_not_supported_for_all_group_members">Bu mesaj aşağıdaki grup üyeleri için silinmeyecektir: %1$s</string>
-    <string name="work_intro_more_link_text">Threema Work hakkında daha fazla bilgi edinin</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">${app_name} hakkında daha fazla bilgi edinin</string>
     <string name="work_intro_subtitle">Şirketler için güvenli mesajlaşma aracı.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Giriş ${app_name}</string>
@@ -1839,6 +1840,10 @@ sunucularımıza güvenli bir şekilde iletildi. Kişisel anahtar hiçbir zaman
     <string name="contact_availability_status_available">Mevcut</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Kullanılamıyor</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">Sağlanan sunucu adresi geçersiz. Lütfen yöneticinizle iletişime geçin.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Aktivasyon bağlantısı geçersiz. Lütfen yöneticinizle iletişime geçin.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d kişi</item>
         <item quantity="other">%d kişi</item>

+ 8 - 3
app/src/main/res/values-uk/strings.xml

@@ -233,7 +233,7 @@
     <string name="threema_version">Версія</string>
     <string name="threema_version_code">Код версії</string>
     <!-- Section title on "About" screen, for section which shows information about the (on prem) server and user credentials -->
-    <string name="about_server_config_title">Конфігурація серверу</string>
+    <string name="about_server_config_title">Конфігурація сервера</string>
     <string name="wrong_backupid_or_password_or_no_internet_connection">Немає з\'єднання з Інтернетом, недійсні дані експортованого ID або неправильний пароль</string>
     <string name="prefs_header_other">Інше</string>
     <string name="an_error_occurred">Сталася помилка</string>
@@ -677,7 +677,7 @@
     <string name="notifications_mute">Вимк.</string>
     <string name="notifications_choose_sound">Вибрати звук</string>
     <string name="error_video_conversion">Не вдалося перетворити відео.</string>
-    <string name="confirm_your_pin">Підтвердження PIN-коду</string>
+    <string name="confirm_your_pin">Перевірка PIN-коду</string>
     <string name="too_many_incorrect_attempts">Забагато невдалих спроб. Повторіть спробу через %s с.</string>
     <string name="no_lockscreen_set">Не встановлено блокування екрана.</string>
     <string name="on">увімкнено</string>
@@ -1772,7 +1772,8 @@
     <string name="new_group_messages">Нові групові повідомлення</string>
     <string name="individual_notification_settings">Індивідуальні налаштування сповіщень</string>
     <string name="delete_message_not_supported_for_all_group_members">Це повідомлення не буде видалено для таких учасників групи: %1$s</string>
-    <string name="work_intro_more_link_text">Докладніше про Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Докладніше про додаток ${app_name}</string>
     <string name="work_intro_subtitle">Безпечний месенджер\nдля компаній.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Увійти в ${app_name}</string>
@@ -1880,6 +1881,10 @@
     <string name="contact_availability_status_available">Доступний</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Недоступний</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">Указана URL-адреса сервера недійсна. Зверніться до свого адміністратора.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">Посилання для активації недійсне. Зверніться до свого адміністратора.</string>
     <plurals name="contacts_counter_label">
         <item quantity="one">%d контакт</item>
         <item quantity="few">%d контакти</item>

+ 6 - 1
app/src/main/res/values-zh-rCN/strings.xml

@@ -1761,7 +1761,8 @@ ${app_name_short} 支持的所有表情符号。</string>
     <string name="new_group_messages">新的群组消息</string>
     <string name="individual_notification_settings">单独通知设置</string>
     <string name="delete_message_not_supported_for_all_group_members">此消息不会为以下群组成员删除:%1$s</string>
-    <string name="work_intro_more_link_text">进一步了解 Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">了解更多有关 ${app_name} 的信息</string>
     <string name="work_intro_subtitle">为公司而设的安全商业版通讯工具。</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">登录 ${app_name}</string>
@@ -1866,6 +1867,10 @@ ${app_name_short} 支持的所有表情符号。</string>
     <string name="contact_availability_status_available">在线</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">离线</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">您所提供的服务器网址为无效,请联系您的管理员以获取帮助。</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">激活链接为无效,请联系您的管理员以获取帮助。</string>
     <plurals name="contacts_counter_label">
         <item quantity="other">%d个联系人</item>
     </plurals>

+ 6 - 1
app/src/main/res/values-zh-rTW/strings.xml

@@ -1760,7 +1760,8 @@ ${app_name_short} 支援的所有表情符號。</string>
     <string name="new_group_messages">新的群組訊息</string>
     <string name="individual_notification_settings">個別通知設定</string>
     <string name="delete_message_not_supported_for_all_group_members">此訊息不會為以下群組成員刪除:%1$s</string>
-    <string name="work_intro_more_link_text">進一步了解 Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">了解更多關於 ${app_name} 的資訊</string>
     <string name="work_intro_subtitle">為公司而設的安全商業版即時通訊工具。</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">登入 ${app_name}</string>
@@ -1865,6 +1866,10 @@ ${app_name_short} 支援的所有表情符號。</string>
     <string name="contact_availability_status_available">上線</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">離線</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">您所提供的伺服器網址為無效,請聯絡您的管理員以取得協助。</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">啟動連結為無效,請聯絡您的管理員以取得協助。</string>
     <plurals name="contacts_counter_label">
         <item quantity="other">%d位聯絡人</item>
     </plurals>

+ 2 - 2
app/src/main/res/values/colors.xml

@@ -11,8 +11,8 @@
     <color name="brand_500">#40E692</color>
     <color name="brand_600">#36D588</color>
     <color name="brand_700">#2CC47E</color>
-    <color name="brand_800">#0E9061</color>
-    <color name="brand_900">#0B734E</color>
+    <color name="brand_800">#0B734E</color>
+    <color name="brand_900">#00412A</color>
 
     <!-- Changes here must also be made to BrandGreyColors.kt for Compose -->
     <color name="brand_grey_50">#F4F4F3</color>

+ 6 - 6
app/src/main/res/values/colors_theme.xml

@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <color name="seed">@color/brand_700</color>
+    <color name="seed">@color/brand_800</color>
 
     <!-- LIGHT -->
 
     <!-- Primary -->
-    <color name="md_theme_light_primary">@color/brand_700</color>
+    <color name="md_theme_light_primary">@color/brand_800</color>
     <color name="md_theme_light_onPrimary">#FFFFFF</color>
-    <color name="md_theme_light_primaryContainer">@color/brand_700</color>
+    <color name="md_theme_light_primaryContainer">@color/brand_800</color>
     <color name="md_theme_light_onPrimaryContainer">#FFFFFF</color>
-    <color name="md_theme_light_inversePrimary">@color/brand_500</color>
+    <color name="md_theme_light_inversePrimary">@color/brand_600</color>
 
     <!-- Secondary -->
-    <color name="md_theme_light_secondary">@color/brand_300</color>
+    <color name="md_theme_light_secondary">@color/brand_400</color>
     <color name="md_theme_light_onSecondary">@color/brand_900</color>
-    <color name="md_theme_light_secondaryContainer">@color/brand_300</color>
+    <color name="md_theme_light_secondaryContainer">@color/brand_400</color>
     <color name="md_theme_light_onSecondaryContainer">@color/brand_900</color>
 
     <!-- Tertiary -->

+ 6 - 1
app/src/main/res/values/strings.xml

@@ -1772,7 +1772,8 @@
     <string name="new_group_messages">New group messages</string>
     <string name="individual_notification_settings">Individual notification settings</string>
     <string name="delete_message_not_supported_for_all_group_members">The message will not be deleted for the following group members: %1$s</string>
-    <string name="work_intro_more_link_text">Find out more about Threema Work</string>
+    <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
+    <string name="work_intro_more_link_text">Find out more about ${app_name}</string>
     <string name="work_intro_subtitle">The secure business messenger\nfor companies.</string>
     <!-- ${app_name} is a placeholder for the app's name, e.g. "Threema". It must be left as-is and not translated. -->
     <string name="work_intro_login">Login ${app_name}</string>
@@ -1891,6 +1892,10 @@
     <string name="contact_availability_status_available">Available</string>
     <!-- Status of a contact (only relevant for Work), e.g. as shown on their profile, indicating that the person is currently not available, i.e., busy or out-of-office -->
     <string name="contact_availability_status_unavailable">Unavailable</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by mdm. -->
+    <string name="error_preset_onprem_url_mismatch_mdm">The provided server url is invalid. Please contact your administrator.</string>
+    <!-- Error message (only relevant for OnPrem) if the preset server url is different from the one provided by the activation link. -->
+    <string name="error_preset_onprem_url_mismatch_intent">The activation link is invalid. Please contact your administrator.</string>
 
     <plurals name="contacts_counter_label">
         <item quantity="one">%d contact</item>

+ 8 - 4
app/src/main/res/values/styles.xml

@@ -729,8 +729,12 @@
     <!-- square button with icon only -->
     <style name="Threema.MaterialButton.Icon" parent="@style/Widget.Material3.Button.IconButton.Filled.Tonal">
         <item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.Medium</item>
-        <item name="backgroundColor">?attr/colorSecondaryContainer</item>
-        <item name="iconTint">?attr/colorOnSecondaryContainer</item>
+        <item name="materialThemeOverlay">@style/ThemeOverlay.Threema.MaterialButton.Icon</item>
+    </style>
+    <style name="ThemeOverlay.Threema.MaterialButton.Icon" parent="ThemeOverlay.Material3.Button.IconButton.Filled.Tonal">
+        <item name="colorContainer">?attr/colorSurfaceContainer</item>
+        <item name="colorOnContainer">?attr/colorPrimary</item>
+        <item name="colorOnContainerUnchecked">?attr/colorPrimary</item>
     </style>
 
     <!-- outline text button with icon -->
@@ -830,8 +834,8 @@
     <style name="Threema.Chip.VideoTranscoder" parent="@style/Widget.Material3.Chip.Assist">
         <item name="android:textAppearance">@style/Threema.TextAppearance.Chip.VideoTranscoder
         </item>
-        <item name="android:textColor">?attr/colorOnSurface</item>
-        <item name="chipBackgroundColor">?attr/colorSurfaceContainerLow</item>
+        <item name="android:textColor">?attr/colorOnPrimaryContainer</item>
+        <item name="chipBackgroundColor">?attr/colorPrimaryContainer</item>
         <item name="chipCornerRadius">14dp</item>
         <item name="chipMinTouchTargetSize">36dp</item>
         <item name="chipMinHeight">28dp</item>

+ 2 - 1
app/src/main/res/values/untranslatable_strings.xml

@@ -23,7 +23,8 @@
     <string name="threema_safe_password_faq" translatable="false">https://threema.com/%s/faq/safepw</string>
     <string name="threema_passwords_faq" translatable="false">https://threema.com/%s/faq/lost_pass</string>
     <string name="backup_faq_url" translatable="false">https://threema.com/%s/faq/data_backup</string>
-    <string name="threema_work_url" translatable="false">https://threema.com/work?li=in-app-work</string>
+    <string name="threema_work_url" translatable="false">https://threema.com/products/work?mtm_campaign=introduction-work-promo&amp;mtm_kwd=android</string>
+    <string name="threema_onprem_url" translatable="false">https://threema.com/products/onprem?mtm_campaign=introduction-onprem-promo&amp;mtm_kwd=android</string>
     <string name="private_download_url" translatable="false">https://play.google.com/store/apps/details?id=ch.threema.app</string>
     <string name="private_download_url_hms" translatable="false">https://appgallery.huawei.com/#/app/C103713829</string>
     <!-- should not be translated because manifest does not allow varying resources-->

+ 2 - 2
app/src/none/java/ch/threema/app/compose/theme/color/BrandColor.kt

@@ -34,6 +34,6 @@ object BrandColor {
     const val SHADE_500 = 0xFF40E692
     const val SHADE_600 = 0xFF36D588
     const val SHADE_700 = 0xFF2CC47E
-    const val SHADE_800 = 0xFF0E9061
-    const val SHADE_900 = 0xFF0B734E
+    const val SHADE_800 = 0xFF0B734E
+    const val SHADE_900 = 0xFF00412A
 }

+ 2 - 2
app/src/onprem/res/drawable/ic_notification_small.xml

@@ -4,6 +4,6 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:pathData="M11.997,0C18.612,0 24,5.383 24,12C24,18.617 18.618,24 12.003,24C9.562,24 7.296,23.271 5.401,22.017L0.789,23.494L2.286,19.035C0.85,17.059 0,14.624 0,12C0,5.383 5.382,0 11.997,0ZM11.852,5.74C11.095,5.74 10.403,5.87 9.777,6.13C9.152,6.39 8.612,6.772 8.158,7.275C7.704,7.773 7.354,8.385 7.104,9.11C6.856,9.835 6.73,10.665 6.73,11.601V12.314C6.731,13.25 6.856,14.08 7.104,14.805C7.359,15.529 7.719,16.144 8.184,16.647C8.648,17.145 9.204,17.524 9.852,17.784C10.499,18.039 11.218,18.166 12.01,18.166C12.884,18.166 13.637,18.075 14.268,17.893C14.898,17.704 15.416,17.48 15.82,17.22C16.23,16.96 16.534,16.716 16.733,16.489V11.617H11.877V13.501H14.027V15.51C13.95,15.587 13.834,15.674 13.679,15.768C13.524,15.856 13.324,15.93 13.081,15.991C12.838,16.046 12.538,16.074 12.185,16.074C11.731,16.074 11.332,15.994 10.989,15.834C10.652,15.674 10.372,15.438 10.15,15.128C9.929,14.813 9.761,14.42 9.645,13.949C9.534,13.479 9.479,12.934 9.479,12.314V11.584C9.479,10.964 9.534,10.422 9.645,9.957C9.755,9.487 9.916,9.094 10.126,8.778C10.336,8.463 10.593,8.227 10.898,8.072C11.207,7.912 11.554,7.832 11.936,7.832C12.411,7.832 12.799,7.912 13.098,8.072C13.396,8.227 13.626,8.452 13.786,8.745C13.952,9.038 14.063,9.387 14.118,9.791H16.725C16.642,9 16.42,8.299 16.06,7.69C15.706,7.082 15.186,6.606 14.5,6.263C13.814,5.914 12.931,5.74 11.852,5.74Z"
-      android:fillColor="#36D588"/>
+      android:pathData="M12,2c5.51,0 10,4.49 10,10s-4.48,10 -10,10c-2.03,0 -3.92,-0.61 -5.5,-1.65l-3.84,1.23 1.25,-3.72c-1.2,-1.65 -1.91,-3.68 -1.91,-5.86 0,-5.51 4.48,-10 10,-10ZM11.88,6.79c-0.64,0 -1.23,0.12 -1.76,0.35 -0.53,0.23 -0.99,0.55 -1.38,0.98 -0.38,0.43 -0.68,0.95 -0.89,1.56 -0.21,0.61 -0.32,1.3 -0.32,2.06v0.45c0,0.77 0.11,1.45 0.32,2.06 0.21,0.61 0.51,1.13 0.9,1.56 0.39,0.43 0.85,0.76 1.38,0.99 0.53,0.23 1.12,0.34 1.76,0.34s1.22,-0.11 1.75,-0.34c0.53,-0.23 0.99,-0.56 1.37,-0.99 0.39,-0.43 0.68,-0.95 0.89,-1.56 0.21,-0.61 0.32,-1.3 0.32,-2.06v-0.45c0,-0.77 -0.11,-1.45 -0.32,-2.06 -0.21,-0.61 -0.51,-1.13 -0.9,-1.56 -0.38,-0.43 -0.84,-0.76 -1.37,-0.98 -0.53,-0.23 -1.12,-0.35 -1.76,-0.35ZM11.88,8.57c0.33,0 0.62,0.07 0.88,0.21 0.26,0.13 0.48,0.33 0.65,0.6 0.18,0.27 0.31,0.6 0.4,1 0.09,0.39 0.14,0.84 0.14,1.36v0.46c0,0.51 -0.05,0.96 -0.14,1.36 -0.09,0.39 -0.22,0.72 -0.39,1 -0.18,0.27 -0.39,0.48 -0.65,0.62 -0.25,0.14 -0.54,0.21 -0.87,0.21s-0.64,-0.07 -0.9,-0.21c-0.25,-0.14 -0.47,-0.34 -0.64,-0.62 -0.18,-0.27 -0.31,-0.6 -0.4,-1 -0.09,-0.4 -0.13,-0.85 -0.13,-1.36v-0.46c0,-0.51 0.04,-0.96 0.13,-1.36 0.09,-0.4 0.22,-0.73 0.39,-1 0.18,-0.27 0.39,-0.47 0.64,-0.6 0.25,-0.14 0.55,-0.21 0.89,-0.21Z"
+      android:fillColor="#fff"/>
 </vector>

+ 2 - 2
app/src/store_google/java/ch/threema/app/compose/theme/color/BrandColor.kt

@@ -34,6 +34,6 @@ object BrandColor {
     const val SHADE_500 = 0xFF40E692
     const val SHADE_600 = 0xFF36D588
     const val SHADE_700 = 0xFF2CC47E
-    const val SHADE_800 = 0xFF0E9061
-    const val SHADE_900 = 0xFF0B734E
+    const val SHADE_800 = 0xFF0B734E
+    const val SHADE_900 = 0xFF00412A
 }

+ 2 - 2
app/src/store_threema/java/ch/threema/app/compose/theme/color/BrandColor.kt

@@ -34,6 +34,6 @@ object BrandColor {
     const val SHADE_500 = 0xFF40E692
     const val SHADE_600 = 0xFF36D588
     const val SHADE_700 = 0xFF2CC47E
-    const val SHADE_800 = 0xFF0E9061
-    const val SHADE_900 = 0xFF0B734E
+    const val SHADE_800 = 0xFF0B734E
+    const val SHADE_900 = 0xFF00412A
 }

+ 1 - 0
domain/src/main/java/ch/threema/domain/protocol/connection/layer/MonitoringLayer.kt

@@ -134,6 +134,7 @@ internal class MonitoringLayer(
     }
 
     private fun handlePromotedToLeader() {
+        logger.info("Handle RolePromotedToLeader")
         if (!mdController.reflectionQueueDry.isCompleted || mdController.reflectionQueueDry.isCancelled) {
             throw D2mProtocolException("RolePromotedToLeader was received before ReflectionQueueDry")
         }