Threema před 4 roky
rodič
revize
bfdef5ff49
71 změnil soubory, kde provedl 680 přidání a 196 odebrání
  1. 2 2
      app/build.gradle
  2. 6 0
      app/src/main/AndroidManifest.xml
  3. 46 4
      app/src/main/java/ch/threema/app/ThreemaApplication.java
  4. 14 6
      app/src/main/java/ch/threema/app/activities/RecipientListBaseActivity.java
  5. 5 1
      app/src/main/java/ch/threema/app/activities/wizard/WizardBaseActivity.java
  6. 33 18
      app/src/main/java/ch/threema/app/backuprestore/csv/BackupService.java
  7. 11 1
      app/src/main/java/ch/threema/app/fragments/BackupDataFragment.java
  8. 5 0
      app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment4.java
  9. 2 1
      app/src/main/java/ch/threema/app/locationpicker/LocationPickerActivity.java
  10. 19 14
      app/src/main/java/ch/threema/app/messagereceiver/ContactMessageReceiver.java
  11. 1 1
      app/src/main/java/ch/threema/app/messagereceiver/DistributionListMessageReceiver.java
  12. 8 5
      app/src/main/java/ch/threema/app/messagereceiver/GroupMessageReceiver.java
  13. 1 5
      app/src/main/java/ch/threema/app/messagereceiver/MessageReceiver.java
  14. 2 2
      app/src/main/java/ch/threema/app/services/LocaleServiceImpl.java
  15. 21 22
      app/src/main/java/ch/threema/app/services/MessageServiceImpl.java
  16. 3 3
      app/src/main/java/ch/threema/app/utils/AndroidContactUtil.java
  17. 2 2
      app/src/main/java/ch/threema/app/utils/AnimationUtil.java
  18. 2 2
      app/src/main/java/ch/threema/app/utils/AppRestrictionUtil.java
  19. 2 2
      app/src/main/java/ch/threema/app/utils/AvatarConverterUtil.java
  20. 2 2
      app/src/main/java/ch/threema/app/utils/BallotUtil.java
  21. 2 2
      app/src/main/java/ch/threema/app/utils/BiometricUtil.java
  22. 2 2
      app/src/main/java/ch/threema/app/utils/BitmapUtil.java
  23. 2 2
      app/src/main/java/ch/threema/app/utils/BitmapWorkerTask.java
  24. 2 2
      app/src/main/java/ch/threema/app/utils/ConfigUtils.java
  25. 2 2
      app/src/main/java/ch/threema/app/utils/ContactUtil.java
  26. 2 2
      app/src/main/java/ch/threema/app/utils/ConversationNotificationUtil.java
  27. 2 3
      app/src/main/java/ch/threema/app/utils/DNDUtil.java
  28. 3 2
      app/src/main/java/ch/threema/app/utils/DeviceIdUtil.java
  29. 2 2
      app/src/main/java/ch/threema/app/utils/DialogUtil.java
  30. 2 2
      app/src/main/java/ch/threema/app/utils/ExifInterface.java
  31. 3 2
      app/src/main/java/ch/threema/app/utils/ExponentialBackOffUtil.java
  32. 2 2
      app/src/main/java/ch/threema/app/utils/FileUtil.java
  33. 4 2
      app/src/main/java/ch/threema/app/utils/GeoLocationUtil.java
  34. 2 2
      app/src/main/java/ch/threema/app/utils/IconUtil.java
  35. 2 3
      app/src/main/java/ch/threema/app/utils/IntentDataUtil.java
  36. 353 0
      app/src/main/java/ch/threema/app/utils/LinkifyCompatUtil.java
  37. 4 5
      app/src/main/java/ch/threema/app/utils/LinkifyUtil.java
  38. 2 2
      app/src/main/java/ch/threema/app/utils/LoadingUtil.java
  39. 0 5
      app/src/main/java/ch/threema/app/utils/LocationUtil.java
  40. 2 2
      app/src/main/java/ch/threema/app/utils/LogUtil.java
  41. 3 2
      app/src/main/java/ch/threema/app/utils/LoggingUEH.java
  42. 2 2
      app/src/main/java/ch/threema/app/utils/MediaPlayerStateWrapper.java
  43. 2 2
      app/src/main/java/ch/threema/app/utils/MessageUtil.java
  44. 2 2
      app/src/main/java/ch/threema/app/utils/NavigationUtil.java
  45. 2 2
      app/src/main/java/ch/threema/app/utils/PowermanagerUtil.java
  46. 2 2
      app/src/main/java/ch/threema/app/utils/PushUtil.java
  47. 2 2
      app/src/main/java/ch/threema/app/utils/QRScannerUtil.java
  48. 2 2
      app/src/main/java/ch/threema/app/utils/QuoteUtil.java
  49. 3 2
      app/src/main/java/ch/threema/app/utils/SecureDeleteUtil.java
  50. 2 2
      app/src/main/java/ch/threema/app/utils/ShortcutUtil.java
  51. 2 2
      app/src/main/java/ch/threema/app/utils/StreamUtil.java
  52. 2 2
      app/src/main/java/ch/threema/app/utils/SynchronizeContactsUtil.java
  53. 2 2
      app/src/main/java/ch/threema/app/utils/TextUtil.java
  54. 2 2
      app/src/main/java/ch/threema/app/utils/TurnServerCache.java
  55. 3 2
      app/src/main/java/ch/threema/app/utils/VideoUtil.java
  56. 2 2
      app/src/main/java/ch/threema/app/utils/WebRTCUtil.java
  57. 2 2
      app/src/main/java/ch/threema/app/utils/WidgetUtil.java
  58. 6 0
      app/src/main/java/ch/threema/app/voip/receivers/CallRejectReceiver.java
  59. 2 2
      app/src/main/java/ch/threema/app/voip/services/CallRejectService.java
  60. 10 0
      app/src/main/res/drawable/ic_places_free_flying.xml
  61. 1 1
      app/src/main/res/layout/fragment_wizard4.xml
  62. 1 1
      app/src/main/res/values-it/webclient_strings.xml
  63. 3 0
      app/src/onprem/res/values-de/strings.xml
  64. 2 0
      app/src/onprem/res/values/strings.xml
  65. 2 2
      build.gradle
  66. 2 2
      domain/build.gradle
  67. 6 4
      domain/src/main/java/ch/threema/domain/onprem/OnPremConfig.java
  68. 8 5
      domain/src/main/java/ch/threema/domain/onprem/OnPremConfigParser.java
  69. 8 1
      domain/src/main/java/ch/threema/domain/onprem/ServerAddressProviderOnPrem.java
  70. 9 4
      domain/src/main/java/ch/threema/domain/protocol/csp/coders/MessageCoder.java
  71. 1 1
      gradle.properties

+ 2 - 2
app/build.gradle

@@ -20,7 +20,7 @@ if (getGradle().getStartParameter().getTaskRequests().toString().contains("Hms")
 }
 }
 
 
 // version codes
 // version codes
-def app_version = "4.64"
+def app_version = "4.65"
 def beta_suffix = "" // with leading dash
 def beta_suffix = "" // with leading dash
 
 
 /**
 /**
@@ -99,7 +99,7 @@ android {
         vectorDrawables.useSupportLibrary = true
         vectorDrawables.useSupportLibrary = true
         applicationId "ch.threema.app"
         applicationId "ch.threema.app"
         testApplicationId 'ch.threema.app.test'
         testApplicationId 'ch.threema.app.test'
-        versionCode 715
+        versionCode 718
         versionName "${app_version}${beta_suffix}"
         versionName "${app_version}${beta_suffix}"
         resValue "string", "app_name", "Threema"
         resValue "string", "app_name", "Threema"
         // package name used for sync adapter - needs to match mime types below
         // package name used for sync adapter - needs to match mime types below

+ 6 - 0
app/src/main/AndroidManifest.xml

@@ -130,6 +130,10 @@
 		<package android:name="com.asus.mobilemanager" />
 		<package android:name="com.asus.mobilemanager" />
 		<package android:name="com.transsion.phonemanager" />
 		<package android:name="com.transsion.phonemanager" />
 
 
+		<!-- provider for xperia home icon badge counters -->
+		<provider android:authorities="com.sonymobile.home.resourceprovider"
+			android:exported="false" />
+
 		<intent>
 		<intent>
 			<action android:name="miui.intent.action.POWER_HIDE_MODE_APP_LIST"/>
 			<action android:name="miui.intent.action.POWER_HIDE_MODE_APP_LIST"/>
 			<category android:name="android.intent.category.DEFAULT"/>
 			<category android:name="android.intent.category.DEFAULT"/>
@@ -561,6 +565,7 @@
 			android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|touchscreen|keyboard|keyboardHidden|uiMode"
 			android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|touchscreen|keyboard|keyboardHidden|uiMode"
 			android:supportsPictureInPicture="true"
 			android:supportsPictureInPicture="true"
 			android:launchMode="singleTask"
 			android:launchMode="singleTask"
+			android:taskAffinity=".voip.activities.CallActivity"
 			android:excludeFromRecents="true"
 			android:excludeFromRecents="true"
 			android:screenOrientation="sensorPortrait"
 			android:screenOrientation="sensorPortrait"
 			android:theme="@style/Theme.Threema.TransparentStatusbar"
 			android:theme="@style/Theme.Threema.TransparentStatusbar"
@@ -847,6 +852,7 @@
 			android:exported="false"/>
 			android:exported="false"/>
 		<service
 		<service
 			android:name=".voip.services.VoipCallService"
 			android:name=".voip.services.VoipCallService"
+			android:foregroundServiceType="phoneCall|camera|microphone"
 			android:exported="false"/>
 			android:exported="false"/>
 		<service
 		<service
 			android:name=".voip.services.CallRejectService"
 			android:name=".voip.services.CallRejectService"

+ 46 - 4
app/src/main/java/ch/threema/app/ThreemaApplication.java

@@ -24,6 +24,8 @@ package ch.threema.app;
 import android.annotation.SuppressLint;
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ApplicationExitInfo;
 import android.app.NotificationManager;
 import android.app.NotificationManager;
 import android.app.job.JobInfo;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
 import android.app.job.JobScheduler;
@@ -53,8 +55,11 @@ import net.sqlcipher.database.SQLiteException;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.Inet6Address;
 import java.net.Inet6Address;
 import java.net.InetSocketAddress;
 import java.net.InetSocketAddress;
 import java.util.Date;
 import java.util.Date;
@@ -263,6 +268,7 @@ public class ThreemaApplication extends MultiDexApplication implements DefaultLi
 	public static final int SHORTCUTS_UPDATE_JOB_ID = 63340;
 	public static final int SHORTCUTS_UPDATE_JOB_ID = 63340;
 
 
 	private static final String WORKER_IDENTITY_STATES_PERIODIC_NAME = "IdentityStates";
 	private static final String WORKER_IDENTITY_STATES_PERIODIC_NAME = "IdentityStates";
+	private static final String EXIT_REASON_LOGGING_TIMESTAMP = "exit_reason_timestamp";
 
 
 	private static Context context;
 	private static Context context;
 
 
@@ -701,9 +707,7 @@ public class ThreemaApplication extends MultiDexApplication implements DefaultLi
 	}
 	}
 
 
 	@SuppressLint("ApplySharedPref")
 	@SuppressLint("ApplySharedPref")
-	private static void resetPreferences() {
-		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getAppContext());
-
+	private static void resetPreferences(SharedPreferences prefs) {
 		// Fix master key preference state if necessary (could be wrong if user kills app
 		// Fix master key preference state if necessary (could be wrong if user kills app
 		// while disabling master key passphrase).
 		// while disabling master key passphrase).
 		if (masterKey.isProtected() && prefs != null && !prefs.getBoolean(getAppContext().getString(R.string.preferences__masterkey_switch), false)) {
 		if (masterKey.isProtected() && prefs != null && !prefs.getBoolean(getAppContext().getString(R.string.preferences__masterkey_switch), false)) {
@@ -779,7 +783,8 @@ public class ThreemaApplication extends MultiDexApplication implements DefaultLi
 	public static synchronized void reset() {
 	public static synchronized void reset() {
 
 
 		//set default preferences
 		//set default preferences
-		resetPreferences();
+		SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getAppContext());
+		resetPreferences(sharedPreferences);
 
 
 		// init state bitmap cache singleton
 		// init state bitmap cache singleton
 		StateBitmapUtil.init(getAppContext());
 		StateBitmapUtil.init(getAppContext());
@@ -836,6 +841,43 @@ public class ThreemaApplication extends MultiDexApplication implements DefaultLi
 				ConfigUtils.getBuildNumber(getAppContext())
 				ConfigUtils.getBuildNumber(getAppContext())
 			);
 			);
 
 
+			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+				ActivityManager activityManager = (ActivityManager) getAppContext().getSystemService(Context.ACTIVITY_SERVICE);
+				List<ApplicationExitInfo> applicationExitInfos = activityManager.getHistoricalProcessExitReasons(null, 0, 0);
+
+				if (applicationExitInfos.size() > 0) {
+					for (ApplicationExitInfo exitInfo : applicationExitInfos) {
+						long timestampOfLastLog = 0L;
+						if (sharedPreferences != null) {
+							timestampOfLastLog = sharedPreferences.getLong(EXIT_REASON_LOGGING_TIMESTAMP, timestampOfLastLog);
+						}
+
+						if (exitInfo.getTimestamp() > timestampOfLastLog) {
+							logger.info(String.format(Locale.US, "*** App last exited at %s with reason: %d, description: %s", DateUtils.formatDateTime(getAppContext(), exitInfo.getTimestamp(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME), exitInfo.getReason(), exitInfo.getDescription()));
+							if (exitInfo.getReason() == ApplicationExitInfo.REASON_ANR) {
+								try {
+									InputStream traceInputStream = exitInfo.getTraceInputStream();
+									if (traceInputStream != null) {
+										BufferedReader r = new BufferedReader(new InputStreamReader(traceInputStream));
+										StringBuilder s = new StringBuilder();
+										for (String line; (line = r.readLine()) != null; ) {
+											s.append(line).append('\n');
+										}
+										logger.info(s.toString());
+									}
+								} catch (IOException e) {
+									logger.error("Error getting ANR trace", e);
+								}
+							}
+						}
+					}
+
+					if (sharedPreferences != null) {
+						sharedPreferences.edit().putLong(EXIT_REASON_LOGGING_TIMESTAMP, System.currentTimeMillis()).apply();
+					}
+				}
+			}
+
 			// Set up logging
 			// Set up logging
 			setupLogging(preferenceStore);
 			setupLogging(preferenceStore);
 
 

+ 14 - 6
app/src/main/java/ch/threema/app/activities/RecipientListBaseActivity.java

@@ -475,7 +475,7 @@ public class RecipientListBaseActivity extends ThreemaToolbarActivity implements
 									type = guessedType;
 									type = guessedType;
 								}
 								}
 
 
-								addMediaItem(type, uri, textIntent);
+								addMediaItemSharedFromOtherApp(type, uri, textIntent);
 								if (textIntent != null) {
 								if (textIntent != null) {
 									captionText = textIntent;
 									captionText = textIntent;
 								}
 								}
@@ -496,7 +496,7 @@ public class RecipientListBaseActivity extends ThreemaToolbarActivity implements
 									captionText = textIntent;
 									captionText = textIntent;
 									mediaItems.add(new MediaItem(uri, MediaItem.TYPE_FILE, MimeUtil.MIME_TYPE_ZIP, textIntent));
 									mediaItems.add(new MediaItem(uri, MediaItem.TYPE_FILE, MimeUtil.MIME_TYPE_ZIP, textIntent));
 								} else { // if text was shared along with the media item, add that too
 								} else { // if text was shared along with the media item, add that too
-									addMediaItem(type, uri, textIntent);
+									addMediaItemSharedFromOtherApp(type, uri, textIntent);
 								}
 								}
 							}
 							}
 						}
 						}
@@ -509,7 +509,7 @@ public class RecipientListBaseActivity extends ThreemaToolbarActivity implements
 								CharSequence text = clipData.getItemAt(i).getText();
 								CharSequence text = clipData.getItemAt(i).getText();
 
 
 								if (uri1 != null) {
 								if (uri1 != null) {
-									addMediaItem(type, uri1, null);
+									addMediaItemSharedFromOtherApp(type, uri1, null);
 								} else if (!TestUtil.empty(text)) {
 								} else if (!TestUtil.empty(text)) {
 									mediaItems.add(new MediaItem(uri, TYPE_TEXT, MimeUtil.MIME_TYPE_TEXT, text.toString()));
 									mediaItems.add(new MediaItem(uri, TYPE_TEXT, MimeUtil.MIME_TYPE_TEXT, text.toString()));
 								}
 								}
@@ -617,7 +617,7 @@ public class RecipientListBaseActivity extends ThreemaToolbarActivity implements
 									if (mimeType == null) {
 									if (mimeType == null) {
 										mimeType = type;
 										mimeType = type;
 									}
 									}
-									addMediaItem(mimeType, uri, null);
+									addMediaItemSharedFromOtherApp(mimeType, uri, null);
 								}
 								}
 							} else {
 							} else {
 								Toast.makeText(getApplicationContext(), getString(R.string.max_selectable_media_exceeded, MAX_SELECTABLE_IMAGES), Toast.LENGTH_LONG).show();
 								Toast.makeText(getApplicationContext(), getString(R.string.max_selectable_media_exceeded, MAX_SELECTABLE_IMAGES), Toast.LENGTH_LONG).show();
@@ -698,7 +698,7 @@ public class RecipientListBaseActivity extends ThreemaToolbarActivity implements
 		return subject + " - " + text;
 		return subject + " - " + text;
 	}
 	}
 
 
-	private void addMediaItem(String mimeType, @NonNull Uri uri, @Nullable String caption) {
+	private void addMediaItemSharedFromOtherApp(String mimeType, @NonNull Uri uri, @Nullable String caption) {
 		if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(uri.getScheme())) {
 		if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(uri.getScheme())) {
 			String path = uri.getPath();
 			String path = uri.getPath();
 			File applicationDir = new File(getApplicationInfo().dataDir);
 			File applicationDir = new File(getApplicationInfo().dataDir);
@@ -726,7 +726,15 @@ public class RecipientListBaseActivity extends ThreemaToolbarActivity implements
 				}
 				}
 			}
 			}
 		}
 		}
-		mediaItems.add(new MediaItem(uri, mimeType, caption));
+		MediaItem mediaItem = new MediaItem(uri, mimeType, caption);
+
+		// never create a voice message out of a shared audio file - fix default
+		if (mediaItem.getType() == MediaItem.TYPE_VOICEMESSAGE) {
+			mediaItem.setType(MediaItem.TYPE_FILE);
+			mediaItem.setRenderingType(FileData.RENDERING_DEFAULT);
+		}
+
+		mediaItems.add(mediaItem);
 	}
 	}
 
 
 	@SuppressLint("StaticFieldLeak")
 	@SuppressLint("StaticFieldLeak")

+ 5 - 1
app/src/main/java/ch/threema/app/activities/wizard/WizardBaseActivity.java

@@ -190,7 +190,11 @@ public class WizardBaseActivity extends ThreemaAppCompatActivity implements View
 						if (ConfigUtils.isWorkBuild()) {
 						if (ConfigUtils.isWorkBuild()) {
 							needConfirm = TestUtil.empty(number) && TestUtil.empty(email) && TestUtil.empty(getPresetEmail()) && TestUtil.empty(getPresetPhone());
 							needConfirm = TestUtil.empty(number) && TestUtil.empty(email) && TestUtil.empty(getPresetEmail()) && TestUtil.empty(getPresetPhone());
 						} else {
 						} else {
-							needConfirm = TestUtil.empty(number) && TestUtil.empty(getPresetPhone());
+							if (ConfigUtils.isOnPremBuild()) {
+								needConfirm = false;
+							} else {
+								needConfirm = TestUtil.empty(number) && TestUtil.empty(getPresetPhone());
+							}
 						}
 						}
 						if (needConfirm) {
 						if (needConfirm) {
 							WizardDialog wizardDialog = WizardDialog.newInstance(
 							WizardDialog wizardDialog = WizardDialog.newInstance(

+ 33 - 18
app/src/main/java/ch/threema/app/backuprestore/csv/BackupService.java

@@ -171,7 +171,7 @@ public class BackupService extends Service {
 				config = (BackupRestoreDataConfig) intent.getSerializableExtra(EXTRA_BACKUP_RESTORE_DATA_CONFIG);
 				config = (BackupRestoreDataConfig) intent.getSerializableExtra(EXTRA_BACKUP_RESTORE_DATA_CONFIG);
 
 
 				if (config == null || userService.getIdentity() == null || userService.getIdentity().length() == 0) {
 				if (config == null || userService.getIdentity() == null || userService.getIdentity().length() == 0) {
-					stopSelf();
+					safeStopSelf();
 					return START_NOT_STICKY;
 					return START_NOT_STICKY;
 				}
 				}
 
 
@@ -191,15 +191,6 @@ public class BackupService extends Service {
 					}
 					}
 				}
 				}
 
 
-				//first of all, close connection
-				try {
-					serviceManager.stopConnection();
-				} catch (InterruptedException e) {
-					showBackupErrorNotification("BackupService interrupted");
-					stopSelf();
-					return START_NOT_STICKY;
-				}
-
 				boolean success = false;
 				boolean success = false;
 				Date now = new Date();
 				Date now = new Date();
 				DocumentFile zipFile = null;
 				DocumentFile zipFile = null;
@@ -207,7 +198,7 @@ public class BackupService extends Service {
 
 
 				if (backupUri == null) {
 				if (backupUri == null) {
 					showBackupErrorNotification("Destination directory has not been selected yet");
 					showBackupErrorNotification("Destination directory has not been selected yet");
-					stopSelf();
+					safeStopSelf();
 					return START_NOT_STICKY;
 					return START_NOT_STICKY;
 				}
 				}
 
 
@@ -232,12 +223,23 @@ public class BackupService extends Service {
 
 
 				if (zipFile == null || !success) {
 				if (zipFile == null || !success) {
 					showBackupErrorNotification(getString(R.string.backup_data_no_permission));
 					showBackupErrorNotification(getString(R.string.backup_data_no_permission));
-					stopSelf();
+					safeStopSelf();
 					return START_NOT_STICKY;
 					return START_NOT_STICKY;
 				}
 				}
 
 
 				backupFile = zipFile;
 				backupFile = zipFile;
 
 
+				showPersistentNotification();
+
+				// close connection
+				try {
+					serviceManager.stopConnection();
+				} catch (InterruptedException e) {
+					showBackupErrorNotification("BackupService interrupted");
+					stopSelf();
+					return START_NOT_STICKY;
+				}
+
 				new AsyncTask<Void, Void, Boolean>() {
 				new AsyncTask<Void, Void, Boolean>() {
 					@Override
 					@Override
 					protected Boolean doInBackground(Void... params) {
 					protected Boolean doInBackground(Void... params) {
@@ -272,7 +274,7 @@ public class BackupService extends Service {
 
 
 		serviceManager = ThreemaApplication.getServiceManager();
 		serviceManager = ThreemaApplication.getServiceManager();
 		if (serviceManager == null) {
 		if (serviceManager == null) {
-			stopSelf();
+			safeStopSelf();
 			return;
 			return;
 		}
 		}
 
 
@@ -287,7 +289,7 @@ public class BackupService extends Service {
 			preferenceService = serviceManager.getPreferenceService();
 			preferenceService = serviceManager.getPreferenceService();
 		} catch (Exception e) {
 		} catch (Exception e) {
 			logger.error("Exception", e);
 			logger.error("Exception", e);
-			stopSelf();
+			safeStopSelf();
 			return;
 			return;
 		}
 		}
 
 
@@ -302,7 +304,6 @@ public class BackupService extends Service {
 		if (isCanceled) {
 		if (isCanceled) {
 			onFinished(getString(R.string.backup_data_cancelled));
 			onFinished(getString(R.string.backup_data_cancelled));
 		}
 		}
-
 		super.onDestroy();
 		super.onDestroy();
 	}
 	}
 
 
@@ -329,9 +330,6 @@ public class BackupService extends Service {
 
 
 	private boolean backup() {
 	private boolean backup() {
 		String identity = userService.getIdentity();
 		String identity = userService.getIdentity();
-
-		showPersistentNotification();
-
 		try(final ZipOutputStream zipOutputStream = ZipUtil.initializeZipOutputStream(getContentResolver(), backupFile.getUri(), config.getPassword())) {
 		try(final ZipOutputStream zipOutputStream = ZipUtil.initializeZipOutputStream(getContentResolver(), backupFile.getUri(), config.getPassword())) {
 			logger.debug("Creating zip file {}", backupFile.getUri());
 			logger.debug("Creating zip file {}", backupFile.getUri());
 
 
@@ -1393,4 +1391,21 @@ public class BackupService extends Service {
 			});
 			});
 		}
 		}
 	}
 	}
+
+	/**
+	 * Show a fake notification before stopping service in order to prevent Context.startForegroundService() did not then call Service.startForeground() crash
+	 */
+	private void safeStopSelf() {
+		Notification notification = new NotificationBuilderWrapper(this, NOTIFICATION_CHANNEL_BACKUP_RESTORE_IN_PROGRESS, null)
+			.setContentTitle("")
+			.setContentText("").
+				build();
+
+		startForeground(BACKUP_NOTIFICATION_ID, notification);
+		stopForeground(true);
+		isRunning = false;
+		stopSelf();
+	}
 }
 }
+
+

+ 11 - 1
app/src/main/java/ch/threema/app/fragments/BackupDataFragment.java

@@ -239,7 +239,17 @@ public class BackupDataFragment extends Fragment implements
 			if (backupUri == null) {
 			if (backupUri == null) {
 				showPathSelectionIntro();
 				showPathSelectionIntro();
 			} else {
 			} else {
-				checkBatteryOptimizations();
+				DocumentFile documentFile = null;
+				try {
+					documentFile = DocumentFile.fromTreeUri(ThreemaApplication.getAppContext(), backupUri);
+				} catch (IllegalArgumentException e) {
+					logger.error("DocumentFile.fromTreeUri failed", e);
+				}
+				if (documentFile == null || !documentFile.exists()) {
+					showPathSelectionIntro();
+				} else {
+					checkBatteryOptimizations();
+				}
 			}
 			}
 		}
 		}
 	}
 	}

+ 5 - 0
app/src/main/java/ch/threema/app/fragments/wizard/WizardFragment4.java

@@ -26,6 +26,7 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton;
+import android.widget.TextView;
 
 
 import androidx.appcompat.widget.SwitchCompat;
 import androidx.appcompat.widget.SwitchCompat;
 import ch.threema.app.R;
 import ch.threema.app.R;
@@ -53,6 +54,10 @@ public class WizardFragment4 extends WizardFragment {
 
 
 		if (ConfigUtils.isOnPremBuild() && ConfigUtils.isDemoOPServer(preferenceService)) {
 		if (ConfigUtils.isOnPremBuild() && ConfigUtils.isDemoOPServer(preferenceService)) {
 			defaultSwitchValue = false;
 			defaultSwitchValue = false;
+			// Add another warning for dull-witted G**gle reviewers
+			TextView textView = rootView.findViewById(R.id.disabled_by_policy);
+			textView.setText(R.string.new_wizard_info_sync_contacts);
+			textView.setVisibility(View.VISIBLE);
 		}
 		}
 
 
 		if (SynchronizeContactsUtil.isRestrictedProfile(getActivity()) &&
 		if (SynchronizeContactsUtil.isRestrictedProfile(getActivity()) &&

+ 2 - 1
app/src/main/java/ch/threema/app/locationpicker/LocationPickerActivity.java

@@ -335,7 +335,8 @@ public class LocationPickerActivity extends ThreemaActivity implements
 					public void onStyleLoaded(@NonNull Style style) {
 					public void onStyleLoaded(@NonNull Style style) {
 						// Map is set up and the style has loaded. Now you can add data or make other mapView adjustments
 						// Map is set up and the style has loaded. Now you can add data or make other mapView adjustments
 						setupLocationComponent(style);
 						setupLocationComponent(style);
-						zoomToCenter();
+						// hack: delay location query
+						mapView.postDelayed(() -> zoomToCenter(), 500);
 					}
 					}
 				});
 				});
 				mapboxMap.getUiSettings().setAttributionEnabled(false);
 				mapboxMap.getUiSettings().setAttributionEnabled(false);

+ 19 - 14
app/src/main/java/ch/threema/app/messagereceiver/ContactMessageReceiver.java

@@ -35,6 +35,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.List;
 import java.util.UUID;
 import java.util.UUID;
 
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Nullable;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
@@ -47,16 +48,16 @@ import ch.threema.app.utils.NameUtil;
 import ch.threema.app.utils.TestUtil;
 import ch.threema.app.utils.TestUtil;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.utils.LoggingUtil;
 import ch.threema.base.utils.LoggingUtil;
-import ch.threema.domain.protocol.csp.messages.AbstractMessage;
+import ch.threema.base.utils.Utils;
+import ch.threema.domain.models.MessageId;
+import ch.threema.domain.protocol.ThreemaFeature;
 import ch.threema.domain.protocol.blob.BlobUploader;
 import ch.threema.domain.protocol.blob.BlobUploader;
-import ch.threema.domain.protocol.csp.messages.BoxLocationMessage;
-import ch.threema.domain.protocol.csp.messages.BoxTextMessage;
+import ch.threema.domain.protocol.csp.ProtocolDefines;
 import ch.threema.domain.protocol.csp.coders.MessageBox;
 import ch.threema.domain.protocol.csp.coders.MessageBox;
-import ch.threema.domain.models.MessageId;
 import ch.threema.domain.protocol.csp.connection.MessageQueue;
 import ch.threema.domain.protocol.csp.connection.MessageQueue;
-import ch.threema.domain.protocol.csp.ProtocolDefines;
-import ch.threema.domain.protocol.ThreemaFeature;
-import ch.threema.base.utils.Utils;
+import ch.threema.domain.protocol.csp.messages.AbstractMessage;
+import ch.threema.domain.protocol.csp.messages.BoxLocationMessage;
+import ch.threema.domain.protocol.csp.messages.BoxTextMessage;
 import ch.threema.domain.protocol.csp.messages.ballot.BallotCreateMessage;
 import ch.threema.domain.protocol.csp.messages.ballot.BallotCreateMessage;
 import ch.threema.domain.protocol.csp.messages.ballot.BallotData;
 import ch.threema.domain.protocol.csp.messages.ballot.BallotData;
 import ch.threema.domain.protocol.csp.messages.ballot.BallotId;
 import ch.threema.domain.protocol.csp.messages.ballot.BallotId;
@@ -70,6 +71,7 @@ import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.MessageModel;
 import ch.threema.storage.models.MessageModel;
 import ch.threema.storage.models.MessageType;
 import ch.threema.storage.models.MessageType;
 import ch.threema.storage.models.ballot.BallotModel;
 import ch.threema.storage.models.ballot.BallotModel;
+import ch.threema.storage.models.data.LocationDataModel;
 import ch.threema.storage.models.data.MessageContentsType;
 import ch.threema.storage.models.data.MessageContentsType;
 import ch.threema.storage.models.data.media.FileDataModel;
 import ch.threema.storage.models.data.media.FileDataModel;
 
 
@@ -83,8 +85,8 @@ public class ContactMessageReceiver implements MessageReceiver<MessageModel> {
 	private final DatabaseServiceNew databaseServiceNew;
 	private final DatabaseServiceNew databaseServiceNew;
 	private final MessageQueue messageQueue;
 	private final MessageQueue messageQueue;
 	private final IdentityStore identityStore;
 	private final IdentityStore identityStore;
-	private IdListService blackListIdentityService;
-	private ApiService apiService;
+	private final IdListService blackListIdentityService;
+	private final ApiService apiService;
 
 
 	public ContactMessageReceiver(ContactModel contactModel,
 	public ContactMessageReceiver(ContactModel contactModel,
 								  ContactService contactService,
 								  ContactService contactService,
@@ -181,14 +183,17 @@ public class ContactMessageReceiver implements MessageReceiver<MessageModel> {
 	}
 	}
 
 
 	@Override
 	@Override
-	public boolean createBoxedLocationMessage(double lat, double lng, float acc, String poiName, MessageModel messageModel) throws ThreemaException {
+	public boolean createBoxedLocationMessage(@NonNull MessageModel messageModel) throws ThreemaException {
+
+		LocationDataModel locationDataModel = messageModel.getLocationData();
 
 
 		BoxLocationMessage msg = new BoxLocationMessage();
 		BoxLocationMessage msg = new BoxLocationMessage();
-		msg.setLatitude(lat);
-		msg.setLongitude(lng);
-		msg.setAccuracy(acc);
+		msg.setLatitude(locationDataModel.getLatitude());
+		msg.setLongitude(locationDataModel.getLongitude());
+		msg.setAccuracy(locationDataModel.getAccuracy());
 		msg.setToIdentity(this.contactModel.getIdentity());
 		msg.setToIdentity(this.contactModel.getIdentity());
-		msg.setPoiName(poiName);
+		msg.setPoiName(locationDataModel.getPoi());
+		msg.setPoiAddress(locationDataModel.getAddress());
 
 
 		//fix #ANDR-512
 		//fix #ANDR-512
 		//save model after receiving a new message id
 		//save model after receiving a new message id

+ 1 - 1
app/src/main/java/ch/threema/app/messagereceiver/DistributionListMessageReceiver.java

@@ -131,7 +131,7 @@ public class DistributionListMessageReceiver implements MessageReceiver<Distribu
 	}
 	}
 
 
 	@Override
 	@Override
-	public boolean createBoxedLocationMessage(final double lat, final double lng, final float acc, String poiName, final DistributionListMessageModel messageModel) throws ThreemaException {
+	public boolean createBoxedLocationMessage(final DistributionListMessageModel messageModel) throws ThreemaException {
 		return this.handleSendImage(messageModel);
 		return this.handleSendImage(messageModel);
 	}
 	}
 
 

+ 8 - 5
app/src/main/java/ch/threema/app/messagereceiver/GroupMessageReceiver.java

@@ -77,6 +77,7 @@ import ch.threema.storage.models.MessageState;
 import ch.threema.storage.models.MessageType;
 import ch.threema.storage.models.MessageType;
 import ch.threema.storage.models.access.GroupAccessModel;
 import ch.threema.storage.models.access.GroupAccessModel;
 import ch.threema.storage.models.ballot.BallotModel;
 import ch.threema.storage.models.ballot.BallotModel;
+import ch.threema.storage.models.data.LocationDataModel;
 import ch.threema.storage.models.data.MessageContentsType;
 import ch.threema.storage.models.data.MessageContentsType;
 import ch.threema.storage.models.data.media.FileDataModel;
 import ch.threema.storage.models.data.media.FileDataModel;
 
 
@@ -156,14 +157,16 @@ public class GroupMessageReceiver implements MessageReceiver<GroupMessageModel>
 	}
 	}
 
 
 	@Override
 	@Override
-	public boolean createBoxedLocationMessage(final double lat, final double lng, final float acc, final String poiName, GroupMessageModel messageModel) throws ThreemaException {
+	public boolean createBoxedLocationMessage(GroupMessageModel messageModel) throws ThreemaException {
 		return this.sendMessage(messageId -> {
 		return this.sendMessage(messageId -> {
+			final LocationDataModel locationDataModel = messageModel.getLocationData();
 			final GroupLocationMessage msg = new GroupLocationMessage();
 			final GroupLocationMessage msg = new GroupLocationMessage();
 			msg.setMessageId(messageId);
 			msg.setMessageId(messageId);
-			msg.setLatitude(lat);
-			msg.setLongitude(lng);
-			msg.setAccuracy(acc);
-			msg.setPoiName(poiName);
+			msg.setLatitude(locationDataModel.getLatitude());
+			msg.setLongitude(locationDataModel.getLongitude());
+			msg.setAccuracy(locationDataModel.getAccuracy());
+			msg.setPoiName(locationDataModel.getPoi());
+			msg.setPoiAddress(locationDataModel.getAddress());
 
 
 			if (messageId != null) {
 			if (messageId != null) {
 				messageModel.setApiMessageId(messageId.toString());
 				messageModel.setApiMessageId(messageId.toString());

+ 1 - 5
app/src/main/java/ch/threema/app/messagereceiver/MessageReceiver.java

@@ -129,15 +129,11 @@ public interface MessageReceiver<M extends AbstractMessageModel> {
 	/**
 	/**
 	 * send a location message
 	 * send a location message
 	 *
 	 *
-	 * @param lat
-	 * @param lng
-	 * @param acc
-	 * @param poiName
 	 * @param messageModel
 	 * @param messageModel
 	 * @return
 	 * @return
 	 * @throws ThreemaException
 	 * @throws ThreemaException
 	 */
 	 */
-	boolean createBoxedLocationMessage(double lat, double lng, float acc, String poiName, M messageModel) throws ThreemaException;
+	boolean createBoxedLocationMessage(M messageModel) throws ThreemaException;
 
 
 	/**
 	/**
 	 * send a file message
 	 * send a file message

+ 2 - 2
app/src/main/java/ch/threema/app/services/LocaleServiceImpl.java

@@ -45,11 +45,11 @@ public class LocaleServiceImpl implements LocaleService {
 		if (this.countryIsoCode == null) {
 		if (this.countryIsoCode == null) {
 			try {
 			try {
 				TelephonyManager tm = (TelephonyManager) this.context.getSystemService(Context.TELEPHONY_SERVICE);
 				TelephonyManager tm = (TelephonyManager) this.context.getSystemService(Context.TELEPHONY_SERVICE);
-				this.countryIsoCode = tm.getSimCountryIso().toUpperCase();
+				this.countryIsoCode = tm.getSimCountryIso().toUpperCase(Locale.US);
 			}
 			}
 			catch (Exception x) {
 			catch (Exception x) {
 				//do nothing
 				//do nothing
-				//is TELEPHONY_SERVICE disabled?s
+				//is TELEPHONY_SERVICE disabled?
 			}
 			}
 
 
 			if(this.countryIsoCode == null || this.countryIsoCode.length() == 0) {
 			if(this.countryIsoCode == null || this.countryIsoCode.length() == 0) {

+ 21 - 22
app/src/main/java/ch/threema/app/services/MessageServiceImpl.java

@@ -44,7 +44,6 @@ import com.neilalexander.jnacl.NaCl;
 
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.BufferedInputStream;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayInputStream;
@@ -121,6 +120,7 @@ import ch.threema.app.video.transcoder.VideoConfig;
 import ch.threema.app.video.transcoder.VideoTranscoder;
 import ch.threema.app.video.transcoder.VideoTranscoder;
 import ch.threema.base.ProgressListener;
 import ch.threema.base.ProgressListener;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.ThreemaException;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.base.utils.Utils;
 import ch.threema.base.utils.Utils;
 import ch.threema.domain.models.MessageId;
 import ch.threema.domain.models.MessageId;
 import ch.threema.domain.protocol.blob.BlobUploader;
 import ch.threema.domain.protocol.blob.BlobUploader;
@@ -195,7 +195,7 @@ import static ch.threema.app.ui.MediaItem.TYPE_VOICEMESSAGE;
 import static ch.threema.domain.protocol.csp.messages.file.FileData.RENDERING_STICKER;
 import static ch.threema.domain.protocol.csp.messages.file.FileData.RENDERING_STICKER;
 
 
 public class MessageServiceImpl implements MessageService {
 public class MessageServiceImpl implements MessageService {
-	private static final Logger logger = LoggerFactory.getLogger(MessageServiceImpl.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("MessageServiceImpl");
 
 
 	private final MessageQueue messageQueue;
 	private final MessageQueue messageQueue;
 	public static final String MESSAGE_QUEUE_SAVE_FILE = "msgqueue.ser";
 	public static final String MESSAGE_QUEUE_SAVE_FILE = "msgqueue.ser";
@@ -480,13 +480,7 @@ public class MessageServiceImpl implements MessageService {
 
 
 		this.fireOnCreatedMessage(messageModel);
 		this.fireOnCreatedMessage(messageModel);
 
 
-		receiver.createBoxedLocationMessage(
-				location.getLatitude(),
-				location.getLongitude(),
-				location.getAccuracy(),
-				poiName,
-				messageModel);
-
+		receiver.createBoxedLocationMessage(messageModel);
 
 
 		messageModel.setState(receiver.sendMediaData() ? MessageState.SENDING : MessageState.SENT);
 		messageModel.setState(receiver.sendMediaData() ? MessageState.SENDING : MessageState.SENT);
 		receiver.saveLocalModel(messageModel);
 		receiver.saveLocalModel(messageModel);
@@ -2092,6 +2086,7 @@ public class MessageServiceImpl implements MessageService {
 				messageModel);
 				messageModel);
 	}
 	}
 
 
+	@WorkerThread
 	private GroupMessageModel saveGroupMessage(GroupLocationMessage message, GroupMessageModel messageModel) throws SQLException {
 	private GroupMessageModel saveGroupMessage(GroupLocationMessage message, GroupMessageModel messageModel) throws SQLException {
 		GroupModel groupModel = this.groupService.getGroup(message);
 		GroupModel groupModel = this.groupService.getGroup(message);
 		boolean isNewMessage = false;
 		boolean isNewMessage = false;
@@ -2114,15 +2109,16 @@ public class MessageServiceImpl implements MessageService {
 			isNewMessage = true;
 			isNewMessage = true;
 		}
 		}
 
 
-		String address = null;
-		try {
-			address = GeoLocationUtil.getAddressFromLocation(context, message.getLatitude(), message.getLongitude());
-		} catch (IOException e) {
-			logger.error("Exception", e);
-			//do not show this error!
+		String address = message.getPoiAddress();
+		if (TestUtil.empty(address)) {
+			try {
+				address = GeoLocationUtil.getAddressFromLocation(context, message.getLatitude(), message.getLongitude());
+			} catch (IOException e) {
+				logger.error("Exception", e);
+				//do not show this error!
+			}
 		}
 		}
 
 
-
 		messageModel.setLocationData(new LocationDataModel(
 		messageModel.setLocationData(new LocationDataModel(
 				message.getLatitude(),
 				message.getLatitude(),
 				message.getLongitude(),
 				message.getLongitude(),
@@ -2314,6 +2310,7 @@ public class MessageServiceImpl implements MessageService {
 		return success;
 		return success;
 	}
 	}
 
 
+	@WorkerThread
 	private MessageModel saveBoxMessage(BoxLocationMessage message, MessageModel messageModel) {
 	private MessageModel saveBoxMessage(BoxLocationMessage message, MessageModel messageModel) {
 		ContactModel contactModel = this.contactService.getByIdentity(message.getFromIdentity());
 		ContactModel contactModel = this.contactService.getByIdentity(message.getFromIdentity());
 		ContactMessageReceiver r = this.contactService.createReceiver(contactModel);
 		ContactMessageReceiver r = this.contactService.createReceiver(contactModel);
@@ -2325,12 +2322,14 @@ public class MessageServiceImpl implements MessageService {
 			messageModel.setOutbox(false);
 			messageModel.setOutbox(false);
 		}
 		}
 
 
-		String address = null;
-		try {
-			address = GeoLocationUtil.getAddressFromLocation(context, message.getLatitude(), message.getLongitude());
-		} catch (IOException e) {
-			logger.error("Exception", e);
-			//do not show this error!
+		String address = message.getPoiAddress();
+		if (TestUtil.empty(address)) {
+			try {
+				address = GeoLocationUtil.getAddressFromLocation(context, message.getLatitude(), message.getLongitude());
+			} catch (IOException e) {
+				logger.error("Exception", e);
+				//do not show this error!
+			}
 		}
 		}
 
 
 		messageModel.setLocationData(new LocationDataModel(
 		messageModel.setLocationData(new LocationDataModel(

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

@@ -44,7 +44,6 @@ import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.ListMultimap;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Date;
@@ -66,12 +65,13 @@ import ch.threema.app.managers.ServiceManager;
 import ch.threema.app.services.FileService;
 import ch.threema.app.services.FileService;
 import ch.threema.app.services.UserService;
 import ch.threema.app.services.UserService;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.ThreemaException;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ContactModel;
 
 
 import static ch.threema.storage.models.ContactModel.DEFAULT_ANDROID_CONTACT_AVATAR_EXPIRY;
 import static ch.threema.storage.models.ContactModel.DEFAULT_ANDROID_CONTACT_AVATAR_EXPIRY;
 
 
 public class AndroidContactUtil {
 public class AndroidContactUtil {
-	private static final Logger logger = LoggerFactory.getLogger(AndroidContactUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("AndroidContactUtil");
 	private UserService userService;
 	private UserService userService;
 	private FileService fileService;
 	private FileService fileService;
 
 
@@ -223,7 +223,7 @@ public class AndroidContactUtil {
 			}
 			}
 		}
 		}
 
 
-		logger.info("Unable to get avatar for {} lookupKey = {} contactUri = {}", contactModel.getIdentity(), contactModel.getAndroidContactLookupKey(), contactUri);
+		logger.debug("Unable to get avatar for {} lookupKey = {} contactUri = {}", contactModel.getIdentity(), contactModel.getAndroidContactLookupKey(), contactUri);
 		return false;
 		return false;
 	}
 	}
 
 

+ 2 - 2
app/src/main/java/ch/threema/app/utils/AnimationUtil.java

@@ -47,7 +47,6 @@ import android.view.animation.TranslateAnimation;
 import android.widget.LinearLayout;
 import android.widget.LinearLayout;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Nullable;
@@ -58,9 +57,10 @@ import androidx.transition.Fade;
 import androidx.transition.Transition;
 import androidx.transition.Transition;
 import androidx.transition.TransitionManager;
 import androidx.transition.TransitionManager;
 import ch.threema.app.R;
 import ch.threema.app.R;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class AnimationUtil {
 public class AnimationUtil {
-	private static final Logger logger = LoggerFactory.getLogger(AnimationUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("AnimationUtil");
 
 
 	public static void expand(final View v) {
 	public static void expand(final View v) {
 		expand(v, null);
 		expand(v, null);

+ 2 - 2
app/src/main/java/ch/threema/app/utils/AppRestrictionUtil.java

@@ -25,7 +25,6 @@ import android.content.Context;
 import android.os.Bundle;
 import android.os.Bundle;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
@@ -38,10 +37,11 @@ import androidx.annotation.StringRes;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.services.AppRestrictionService;
 import ch.threema.app.services.AppRestrictionService;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class AppRestrictionUtil {
 public class AppRestrictionUtil {
 
 
-	private static final Logger logger = LoggerFactory.getLogger(AppRestrictionUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("AppRestrictionUtil");
 
 
 	public static boolean isAddContactDisabled(Context context) {
 	public static boolean isAddContactDisabled(Context context) {
 		return getBoolRestriction(context, R.string.restriction__disable_add_contact);
 		return getBoolRestriction(context, R.string.restriction__disable_add_contact);

+ 2 - 2
app/src/main/java/ch/threema/app/utils/AvatarConverterUtil.java

@@ -39,7 +39,6 @@ import android.net.Uri;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.IOException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStream;
@@ -52,12 +51,13 @@ import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
 import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
 import ch.threema.app.R;
 import ch.threema.app.R;
+import ch.threema.base.utils.LoggingUtil;
 
 
 import static ch.threema.app.dialogs.ContactEditDialog.CONTACT_AVATAR_HEIGHT_PX;
 import static ch.threema.app.dialogs.ContactEditDialog.CONTACT_AVATAR_HEIGHT_PX;
 import static ch.threema.app.dialogs.ContactEditDialog.CONTACT_AVATAR_WIDTH_PX;
 import static ch.threema.app.dialogs.ContactEditDialog.CONTACT_AVATAR_WIDTH_PX;
 
 
 public class AvatarConverterUtil {
 public class AvatarConverterUtil {
-	private static final Logger logger = LoggerFactory.getLogger(AvatarConverterUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("AvatarConverterUtil");
 
 
 	private static int avatarSize = -1, iconSize = -1, iconOffset = -1;
 	private static int avatarSize = -1, iconSize = -1, iconOffset = -1;
 
 

+ 2 - 2
app/src/main/java/ch/threema/app/utils/BallotUtil.java

@@ -26,7 +26,6 @@ import android.content.Intent;
 import android.widget.Toast;
 import android.widget.Toast;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.security.SecureRandom;
 import java.security.SecureRandom;
 import java.util.List;
 import java.util.List;
@@ -48,6 +47,7 @@ import ch.threema.app.messagereceiver.GroupMessageReceiver;
 import ch.threema.app.messagereceiver.MessageReceiver;
 import ch.threema.app.messagereceiver.MessageReceiver;
 import ch.threema.app.services.UserService;
 import ch.threema.app.services.UserService;
 import ch.threema.app.services.ballot.BallotService;
 import ch.threema.app.services.ballot.BallotService;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.domain.protocol.csp.connection.ConnectionState;
 import ch.threema.domain.protocol.csp.connection.ConnectionState;
 import ch.threema.domain.protocol.csp.connection.MessageTooLongException;
 import ch.threema.domain.protocol.csp.connection.MessageTooLongException;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
@@ -56,7 +56,7 @@ import ch.threema.storage.models.ballot.BallotModel;
 
 
 @SuppressWarnings("rawtypes")
 @SuppressWarnings("rawtypes")
 public class BallotUtil {
 public class BallotUtil {
-	private static final Logger logger = LoggerFactory.getLogger(BallotUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("BallotUtil");
 
 
 	public static boolean canVote(BallotModel model, String identity) {
 	public static boolean canVote(BallotModel model, String identity) {
 		return model != null
 		return model != null

+ 2 - 2
app/src/main/java/ch/threema/app/utils/BiometricUtil.java

@@ -30,7 +30,6 @@ import android.os.Build;
 import android.widget.Toast;
 import android.widget.Toast;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import androidx.biometric.BiometricManager;
 import androidx.biometric.BiometricManager;
 import androidx.core.app.ActivityCompat;
 import androidx.core.app.ActivityCompat;
@@ -38,11 +37,12 @@ import androidx.fragment.app.Fragment;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.activities.BiometricLockActivity;
 import ch.threema.app.activities.BiometricLockActivity;
+import ch.threema.base.utils.LoggingUtil;
 
 
 import static ch.threema.app.activities.BiometricLockActivity.INTENT_DATA_AUTHENTICATION_TYPE;
 import static ch.threema.app.activities.BiometricLockActivity.INTENT_DATA_AUTHENTICATION_TYPE;
 
 
 public class BiometricUtil {
 public class BiometricUtil {
-	private static final Logger logger = LoggerFactory.getLogger(BiometricUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("BiometricUtil");
 
 
 	public static boolean isBiometricsSupported(Context context) {
 	public static boolean isBiometricsSupported(Context context) {
 		String toast = context.getString(R.string.biometrics_not_avilable);
 		String toast = context.getString(R.string.biometrics_not_avilable);

+ 2 - 2
app/src/main/java/ch/threema/app/utils/BitmapUtil.java

@@ -39,7 +39,6 @@ import android.provider.MediaStore;
 import android.view.View;
 import android.view.View;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.BufferedInputStream;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.ByteArrayOutputStream;
@@ -55,9 +54,10 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 import androidx.annotation.WorkerThread;
 import ch.threema.app.webclient.utils.ThumbnailUtils;
 import ch.threema.app.webclient.utils.ThumbnailUtils;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class BitmapUtil {
 public class BitmapUtil {
-	private static final Logger logger = LoggerFactory.getLogger(BitmapUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("BitmapUtil");
 
 
 	private static final int DEFAULT_JPG_QUALITY = 80;
 	private static final int DEFAULT_JPG_QUALITY = 80;
 	private static final int DEFAULT_PNG_QUALITY = 100; // PNG is lossless anyway
 	private static final int DEFAULT_PNG_QUALITY = 100; // PNG is lossless anyway

+ 2 - 2
app/src/main/java/ch/threema/app/utils/BitmapWorkerTask.java

@@ -28,7 +28,6 @@ import android.os.AsyncTask;
 import android.widget.ImageView;
 import android.widget.ImageView;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.FileNotFoundException;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.IOException;
@@ -38,11 +37,12 @@ import java.lang.ref.WeakReference;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.appcompat.content.res.AppCompatResources;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
+import ch.threema.base.utils.LoggingUtil;
 
 
 import static ch.threema.app.utils.BitmapUtil.FLIP_NONE;
 import static ch.threema.app.utils.BitmapUtil.FLIP_NONE;
 
 
 public class BitmapWorkerTask extends AsyncTask<BitmapWorkerTaskParams, Void, Bitmap> {
 public class BitmapWorkerTask extends AsyncTask<BitmapWorkerTaskParams, Void, Bitmap> {
-	private static final Logger logger = LoggerFactory.getLogger(BitmapWorkerTask.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("BitmapWorkerTask");
 
 
 	private final WeakReference<ImageView> imageViewReference;
 	private final WeakReference<ImageView> imageViewReference;
 
 

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

@@ -67,7 +67,6 @@ import com.google.android.material.snackbar.BaseTransientBottomBar;
 import com.google.android.material.snackbar.Snackbar;
 import com.google.android.material.snackbar.Snackbar;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.RetentionPolicy;
@@ -112,6 +111,7 @@ import ch.threema.app.services.LockAppService;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.license.LicenseService;
 import ch.threema.app.services.license.LicenseService;
 import ch.threema.app.threemasafe.ThreemaSafeConfigureActivity;
 import ch.threema.app.threemasafe.ThreemaSafeConfigureActivity;
+import ch.threema.base.utils.LoggingUtil;
 
 
 import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
 import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
 import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
@@ -124,7 +124,7 @@ import static ch.threema.app.services.NotificationService.NOTIFICATION_CHANNEL_A
 import static ch.threema.app.services.NotificationServiceImpl.APP_RESTART_NOTIFICATION_ID;
 import static ch.threema.app.services.NotificationServiceImpl.APP_RESTART_NOTIFICATION_ID;
 
 
 public class ConfigUtils {
 public class ConfigUtils {
-	private static final Logger logger = LoggerFactory.getLogger(ConfigUtils.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("ConfigUtils");
 
 
 	public static final int THEME_LIGHT = 0;
 	public static final int THEME_LIGHT = 0;
 	public static final int THEME_DARK = 1;
 	public static final int THEME_DARK = 1;

+ 2 - 2
app/src/main/java/ch/threema/app/utils/ContactUtil.java

@@ -29,7 +29,6 @@ import android.provider.ContactsContract;
 import android.text.TextUtils;
 import android.text.TextUtils;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.Date;
 import java.util.Date;
 
 
@@ -41,10 +40,11 @@ import ch.threema.app.ThreemaApplication;
 import ch.threema.app.services.FileService;
 import ch.threema.app.services.FileService;
 import ch.threema.app.services.IdListService;
 import ch.threema.app.services.IdListService;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.PreferenceService;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ContactModel;
 
 
 public class ContactUtil {
 public class ContactUtil {
-	private static final Logger logger = LoggerFactory.getLogger(ContactUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("ContactUtil");
 
 
 	public static final int CHANNEL_NAME_MAX_LENGTH_BYTES = 256;
 	public static final int CHANNEL_NAME_MAX_LENGTH_BYTES = 256;
 
 

+ 2 - 2
app/src/main/java/ch/threema/app/utils/ConversationNotificationUtil.java

@@ -25,7 +25,6 @@ import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.Date;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
@@ -43,6 +42,7 @@ import ch.threema.app.services.GroupService;
 import ch.threema.app.services.MessageService;
 import ch.threema.app.services.MessageService;
 import ch.threema.app.services.NotificationService;
 import ch.threema.app.services.NotificationService;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.ThreemaException;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.domain.protocol.csp.messages.file.FileData;
 import ch.threema.domain.protocol.csp.messages.file.FileData;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ContactModel;
@@ -53,7 +53,7 @@ import ch.threema.storage.models.MessageType;
 import ch.threema.storage.models.data.MessageContentsType;
 import ch.threema.storage.models.data.MessageContentsType;
 
 
 public class ConversationNotificationUtil {
 public class ConversationNotificationUtil {
-	private static final Logger logger = LoggerFactory.getLogger(ConversationNotificationUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("ConversationNotificationUtil");
 
 
 	protected static final HashMap<String, NotificationService.ConversationNotificationGroup> notificationGroupHashMap = new HashMap<>();
 	protected static final HashMap<String, NotificationService.ConversationNotificationGroup> notificationGroupHashMap = new HashMap<>();
 
 

+ 2 - 3
app/src/main/java/ch/threema/app/utils/DNDUtil.java

@@ -33,7 +33,6 @@ import android.os.Build;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.Calendar;
 import java.util.Calendar;
 import java.util.Set;
 import java.util.Set;
@@ -51,11 +50,11 @@ import ch.threema.app.services.ContactService;
 import ch.threema.app.services.DeadlineListService;
 import ch.threema.app.services.DeadlineListService;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.stores.IdentityStore;
 import ch.threema.app.stores.IdentityStore;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ContactModel;
 
 
-
 public class DNDUtil {
 public class DNDUtil {
-	private static final Logger logger = LoggerFactory.getLogger(DNDUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("DNDUtil");
 	private DeadlineListService mutedChatsListService;
 	private DeadlineListService mutedChatsListService;
 	private DeadlineListService mentionOnlyChatsListService;
 	private DeadlineListService mentionOnlyChatsListService;
 	private final IdentityStore identityStore;
 	private final IdentityStore identityStore;

+ 3 - 2
app/src/main/java/ch/threema/app/utils/DeviceIdUtil.java

@@ -25,14 +25,15 @@ import android.content.Context;
 
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
 import java.util.UUID;
 import java.util.UUID;
 
 
+import ch.threema.base.utils.LoggingUtil;
+
 public class DeviceIdUtil {
 public class DeviceIdUtil {
-	private static final Logger logger = LoggerFactory.getLogger(DeviceIdUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("DeviceIdUtil");
 
 
 	private static final String DEVICE_ID_FILENAME = "device_id";
 	private static final String DEVICE_ID_FILENAME = "device_id";
 
 

+ 2 - 2
app/src/main/java/ch/threema/app/utils/DialogUtil.java

@@ -26,7 +26,6 @@ import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.content.res.TypedArray;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import androidx.annotation.UiThread;
 import androidx.annotation.UiThread;
 import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.DialogFragment;
@@ -34,9 +33,10 @@ import androidx.fragment.app.FragmentManager;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.dialogs.CancelableHorizontalProgressDialog;
 import ch.threema.app.dialogs.CancelableHorizontalProgressDialog;
 import ch.threema.app.dialogs.GenericProgressDialog;
 import ch.threema.app.dialogs.GenericProgressDialog;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public abstract class DialogUtil {
 public abstract class DialogUtil {
-	private static final Logger logger = LoggerFactory.getLogger(DialogUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("DialogUtil");
 
 
 	public static void dismissDialog(FragmentManager fragmentManager, String tag, boolean allowStateLoss) {
 	public static void dismissDialog(FragmentManager fragmentManager, String tag, boolean allowStateLoss) {
 		logger.debug("dismissDialog: " + tag);
 		logger.debug("dismissDialog: " + tag);

+ 2 - 2
app/src/main/java/ch/threema/app/utils/ExifInterface.java

@@ -41,7 +41,6 @@ import android.os.Build;
 import android.util.Pair;
 import android.util.Pair;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.BufferedInputStream;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayInputStream;
@@ -83,6 +82,7 @@ import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo;
+import ch.threema.base.utils.LoggingUtil;
 
 
 import static ch.threema.base.utils.Utils.byteArrayToHexString;
 import static ch.threema.base.utils.Utils.byteArrayToHexString;
 import static java.nio.charset.StandardCharsets.US_ASCII;
 import static java.nio.charset.StandardCharsets.US_ASCII;
@@ -95,7 +95,7 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
  * Attribute mutation is supported for JPEG image files.
  * Attribute mutation is supported for JPEG image files.
  */
  */
 public class ExifInterface {
 public class ExifInterface {
-	private static final Logger logger = LoggerFactory.getLogger(ExifInterface.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("ExifInterface");
 
 
 	private static final boolean DEBUG = false;
 	private static final boolean DEBUG = false;
 
 

+ 3 - 2
app/src/main/java/ch/threema/app/utils/ExponentialBackOffUtil.java

@@ -22,15 +22,16 @@
 package ch.threema.app.utils;
 package ch.threema.app.utils;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.Random;
 import java.util.Random;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.Future;
 
 
+import ch.threema.base.utils.LoggingUtil;
+
 public class ExponentialBackOffUtil {
 public class ExponentialBackOffUtil {
-	private static final Logger logger = LoggerFactory.getLogger(ExponentialBackOffUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("ExponentialBackOffUtil");
 	protected final static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
 	protected final static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
 	private Random random;
 	private Random random;
 
 

+ 2 - 2
app/src/main/java/ch/threema/app/utils/FileUtil.java

@@ -43,7 +43,6 @@ import android.widget.Toast;
 
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileInputStream;
@@ -66,6 +65,7 @@ import ch.threema.app.camera.CameraActivity;
 import ch.threema.app.filepicker.FilePickerActivity;
 import ch.threema.app.filepicker.FilePickerActivity;
 import ch.threema.app.services.FileService;
 import ch.threema.app.services.FileService;
 import ch.threema.app.ui.MediaItem;
 import ch.threema.app.ui.MediaItem;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.data.media.FileDataModel;
 import ch.threema.storage.models.data.media.FileDataModel;
 
 
@@ -73,7 +73,7 @@ import static ch.threema.app.ThreemaApplication.MAX_BLOB_SIZE;
 import static ch.threema.app.filepicker.FilePickerActivity.INTENT_DATA_DEFAULT_PATH;
 import static ch.threema.app.filepicker.FilePickerActivity.INTENT_DATA_DEFAULT_PATH;
 
 
 public class FileUtil {
 public class FileUtil {
-	private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("FileUtil");
 
 
 	private FileUtil() {
 	private FileUtil() {
 
 

+ 4 - 2
app/src/main/java/ch/threema/app/utils/GeoLocationUtil.java

@@ -32,7 +32,6 @@ import android.os.Message;
 import android.widget.TextView;
 import android.widget.TextView;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.IOException;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.net.URLEncoder;
@@ -41,13 +40,15 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map;
 
 
+import androidx.annotation.WorkerThread;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.services.MessageService;
 import ch.threema.app.services.MessageService;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.data.LocationDataModel;
 import ch.threema.storage.models.data.LocationDataModel;
 
 
 public class GeoLocationUtil {
 public class GeoLocationUtil {
-	private static final Logger logger = LoggerFactory.getLogger(GeoLocationUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("GeoLocationUtil");
 
 
 	private TextView targetView;
 	private TextView targetView;
 
 
@@ -57,6 +58,7 @@ public class GeoLocationUtil {
 		this.targetView = targetView;
 		this.targetView = targetView;
 	}
 	}
 
 
+	@WorkerThread
 	public static String getAddressFromLocation(Context context, double latitude, double longitude) throws IOException {
 	public static String getAddressFromLocation(Context context, double latitude, double longitude) throws IOException {
 		String addressString = context.getString(R.string.unknown_address);
 		String addressString = context.getString(R.string.unknown_address);
 		String key = String.valueOf(latitude) + '|' + String.valueOf(longitude);
 		String key = String.valueOf(latitude) + '|' + String.valueOf(longitude);

+ 2 - 2
app/src/main/java/ch/threema/app/utils/IconUtil.java

@@ -37,19 +37,19 @@ import android.provider.MediaStore;
 
 
 import org.msgpack.core.annotations.Nullable;
 import org.msgpack.core.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.HashMap;
 import java.util.HashMap;
 
 
 import androidx.annotation.WorkerThread;
 import androidx.annotation.WorkerThread;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.ui.MediaItem;
 import ch.threema.app.ui.MediaItem;
+import ch.threema.base.utils.LoggingUtil;
 
 
 import static android.media.MediaMetadataRetriever.OPTION_CLOSEST_SYNC;
 import static android.media.MediaMetadataRetriever.OPTION_CLOSEST_SYNC;
 import static ch.threema.app.services.MessageServiceImpl.THUMBNAIL_SIZE_PX;
 import static ch.threema.app.services.MessageServiceImpl.THUMBNAIL_SIZE_PX;
 
 
 public class IconUtil {
 public class IconUtil {
-	private static final Logger logger = LoggerFactory.getLogger(IconUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("IconUtil");
 	private static final HashMap<String, Integer> mimeIcons = new HashMap<>();
 	private static final HashMap<String, Integer> mimeIcons = new HashMap<>();
 
 
 	private static void add(String mimeType, int resId) {
 	private static void add(String mimeType, int resId) {

+ 2 - 3
app/src/main/java/ch/threema/app/utils/IntentDataUtil.java

@@ -31,7 +31,6 @@ import android.os.SystemClock;
 import com.mapbox.mapboxsdk.geometry.LatLng;
 import com.mapbox.mapboxsdk.geometry.LatLng;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Iterator;
@@ -42,7 +41,6 @@ import ch.threema.app.BuildConfig;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.activities.ComposeMessageActivity;
 import ch.threema.app.activities.ComposeMessageActivity;
 import ch.threema.app.activities.HomeActivity;
 import ch.threema.app.activities.HomeActivity;
-import ch.threema.app.activities.RecipientListBaseActivity;
 import ch.threema.app.backuprestore.BackupRestoreDataService;
 import ch.threema.app.backuprestore.BackupRestoreDataService;
 import ch.threema.app.fragments.ComposeMessageFragment;
 import ch.threema.app.fragments.ComposeMessageFragment;
 import ch.threema.app.managers.ServiceManager;
 import ch.threema.app.managers.ServiceManager;
@@ -55,6 +53,7 @@ import ch.threema.app.services.ContactService;
 import ch.threema.app.services.DistributionListService;
 import ch.threema.app.services.DistributionListService;
 import ch.threema.app.services.GroupService;
 import ch.threema.app.services.GroupService;
 import ch.threema.app.services.MessageService;
 import ch.threema.app.services.MessageService;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ConversationModel;
 import ch.threema.storage.models.ConversationModel;
@@ -68,7 +67,7 @@ import ch.threema.storage.models.ballot.BallotModel;
 import ch.threema.storage.models.group.GroupInviteModel;
 import ch.threema.storage.models.group.GroupInviteModel;
 
 
 public class IntentDataUtil {
 public class IntentDataUtil {
-	private static final Logger logger = LoggerFactory.getLogger(RecipientListBaseActivity.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("RecipientListBaseActivity");
 
 
 	public static final String ACTION_LICENSE_NOT_ALLOWED = BuildConfig.APPLICATION_ID + "license_not_allowed";
 	public static final String ACTION_LICENSE_NOT_ALLOWED = BuildConfig.APPLICATION_ID + "license_not_allowed";
 	public static final String ACTION_CONTACTS_CHANGED = BuildConfig.APPLICATION_ID + "contacts_changed";
 	public static final String ACTION_CONTACTS_CHANGED = BuildConfig.APPLICATION_ID + "contacts_changed";

+ 353 - 0
app/src/main/java/ch/threema/app/utils/LinkifyCompatUtil.java

@@ -0,0 +1,353 @@
+/*  _____ _
+ * |_   _| |_  _ _ ___ ___ _ __  __ _
+ *   | | | ' \| '_/ -_) -_) '  \/ _` |_
+ *   |_| |_||_|_| \___\___|_|_|_\__,_(_)
+ *
+ * Threema for Android
+ * Copyright (c) 2019-2022 Threema GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.threema.app.utils;
+
+import android.annotation.SuppressLint;
+import android.telephony.PhoneNumberUtils;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.method.MovementMethod;
+import android.text.style.URLSpan;
+import android.text.util.Linkify;
+import android.text.util.Linkify.MatchFilter;
+import android.text.util.Linkify.TransformFilter;
+import android.widget.TextView;
+
+import com.google.i18n.phonenumbers.PhoneNumberMatch;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.PatternsCompat;
+import ch.threema.app.ThreemaApplication;
+import ch.threema.app.services.LocaleService;
+
+/**
+ * LinkifyCompatUtil is based on AOSPs LinkifyCompat ensuring consistent behaviour across different Android versions
+ * and device manufacturers as well as fixing the lenient phone number handling on some devices
+ */
+public final class LinkifyCompatUtil {
+
+    private static final Comparator<LinkSpec>  COMPARATOR = (a, b) -> {
+        if (a.start < b.start) {
+            return -1;
+        }
+
+        if (a.start > b.start) {
+            return 1;
+        }
+
+	    return Integer.compare(b.end, a.end);
+
+    };
+
+    @IntDef(flag = true, value = { Linkify.WEB_URLS, Linkify.EMAIL_ADDRESSES, Linkify.PHONE_NUMBERS,
+            Linkify.MAP_ADDRESSES, Linkify.ALL })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LinkifyMask {}
+
+    /**
+     *  Scans the text of the provided Spannable and turns all occurrences
+     *  of the link types indicated in the mask into clickable links.
+     *  If the mask is nonzero, it also removes any existing URLSpans
+     *  attached to the Spannable, to avoid problems if you call it
+     *  repeatedly on the same text.
+     *
+     *  @param text Spannable whose text is to be marked-up with links
+     *  @param mask Mask to define which kinds of links will be searched.
+     *
+     *  @return True if at least one link is found and applied.
+     */
+    @SuppressLint("RestrictedApi")
+    public static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
+        if (shouldAddLinksFallbackToFramework()) {
+            return Linkify.addLinks(text, mask);
+        }
+        if (mask == 0) {
+            return false;
+        }
+
+        URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class);
+
+        for (int i = old.length - 1; i >= 0; i--) {
+            text.removeSpan(old[i]);
+        }
+
+	    final ArrayList<LinkSpec> links = new ArrayList<>();
+
+        if ((mask & Linkify.WEB_URLS) != 0) {
+            gatherLinks(links, text, PatternsCompat.AUTOLINK_WEB_URL,
+                    new String[] { "http://", "https://", "rtsp://" },
+                    Linkify.sUrlMatchFilter, null);
+        }
+
+        if ((mask & Linkify.EMAIL_ADDRESSES) != 0) {
+            gatherLinks(links, text, PatternsCompat.AUTOLINK_EMAIL_ADDRESS,
+                    new String[] { "mailto:" },
+                    null, null);
+        }
+
+        // Threema-added
+	    if ((mask & Linkify.PHONE_NUMBERS) != 0) {
+		    gatherTelLinks(links, text);
+	    }
+
+	    pruneOverlaps(links, text);
+
+        if (links.size() == 0) {
+            return false;
+        }
+
+        for (LinkSpec link: links) {
+            if (link.frameworkAddedSpan == null) {
+                applyLink(link.url, link.start, link.end, text);
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     *  Scans the text of the provided TextView and turns all occurrences of
+     *  the link types indicated in the mask into clickable links.  If matches
+     *  are found the movement method for the TextView is set to
+     *  LinkMovementMethod.
+     *
+     *  @param text TextView whose text is to be marked-up with links
+     *  @param mask Mask to define which kinds of links will be searched.
+     *
+     *  @return True if at least one link is found and applied.
+     */
+    public static boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
+        if (shouldAddLinksFallbackToFramework()) {
+            return Linkify.addLinks(text, mask);
+        }
+        if (mask == 0) {
+            return false;
+        }
+
+        CharSequence t = text.getText();
+
+        if (t instanceof Spannable) {
+            if (addLinks((Spannable) t, mask)) {
+                addLinkMovementMethod(text);
+                return true;
+            }
+
+            return false;
+        } else {
+            SpannableString s = SpannableString.valueOf(t);
+
+            if (addLinks(s, mask)) {
+                addLinkMovementMethod(text);
+                text.setText(s);
+
+                return true;
+            }
+
+            return false;
+        }
+    }
+
+    private static boolean shouldAddLinksFallbackToFramework() {
+    	// Threema-added: Never use the system's linkify
+        return false;
+		// return Build.VERSION.SDK_INT >= 28;
+    }
+
+    private static void addLinkMovementMethod(@NonNull TextView t) {
+        MovementMethod m = t.getMovementMethod();
+
+        if (!(m instanceof LinkMovementMethod)) {
+            if (t.getLinksClickable()) {
+                t.setMovementMethod(LinkMovementMethod.getInstance());
+            }
+        }
+    }
+
+    private static String makeUrl(@NonNull String url, @NonNull String[] prefixes,
+            Matcher matcher, @Nullable TransformFilter filter) {
+        if (filter != null) {
+            url = filter.transformUrl(matcher, url);
+        }
+
+        boolean hasPrefix = false;
+
+        for (int i = 0; i < prefixes.length; i++) {
+            if (url.regionMatches(true, 0, prefixes[i], 0, prefixes[i].length())) {
+                hasPrefix = true;
+
+                // Fix capitalization if necessary
+                if (!url.regionMatches(false, 0, prefixes[i], 0, prefixes[i].length())) {
+                    url = prefixes[i] + url.substring(prefixes[i].length());
+                }
+
+                break;
+            }
+        }
+
+        if (!hasPrefix && prefixes.length > 0) {
+            url = prefixes[0] + url;
+        }
+
+        return url;
+    }
+
+    private static void gatherLinks(ArrayList<LinkSpec> links,
+            Spannable s, Pattern pattern, String[] schemes,
+            MatchFilter matchFilter, TransformFilter transformFilter) {
+        Matcher m = pattern.matcher(s);
+
+        while (m.find()) {
+            int start = m.start();
+            int end = m.end();
+
+            if (matchFilter == null || matchFilter.acceptMatch(s, start, end)) {
+                LinkSpec spec = new LinkSpec();
+                String url = makeUrl(m.group(0), schemes, m, transformFilter);
+
+                spec.url = url;
+                spec.start = start;
+                spec.end = end;
+
+                links.add(spec);
+            }
+        }
+    }
+
+	private static boolean gatherTelLinks(@NonNull ArrayList<LinkSpec> links, @NonNull Spannable s) {
+    	// Threema-added: try to get the current locale from LocaleService
+    	String countryCode;
+    	try {
+		    LocaleService localeService = ThreemaApplication.getServiceManager().getLocaleService();
+		    countryCode = localeService.getCountryIsoCode();
+	    } catch (Exception e) {
+    		countryCode = Locale.getDefault().getCountry();
+	    }
+		PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
+    	// Threema-changed: only allow for valid phone numbers
+		Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(), countryCode, PhoneNumberUtil.Leniency.VALID, Long.MAX_VALUE);
+		for (PhoneNumberMatch match : matches) {
+			LinkSpec spec = new LinkSpec();
+			spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
+			spec.start = match.start();
+			spec.end = match.end();
+			links.add(spec);
+		}
+		return links.size() > 0;
+	}
+
+	private static void applyLink(String url, int start, int end, Spannable text) {
+        URLSpan span = new URLSpan(url);
+
+        text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+    }
+
+    private static void pruneOverlaps(ArrayList<LinkSpec> links, Spannable text) {
+        // Append spans added by framework
+        URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+        for (int i = 0; i < urlSpans.length; i++) {
+            LinkSpec spec = new LinkSpec();
+            spec.frameworkAddedSpan = urlSpans[i];
+            spec.start = text.getSpanStart(urlSpans[i]);
+            spec.end = text.getSpanEnd(urlSpans[i]);
+            links.add(spec);
+        }
+
+        Collections.sort(links, COMPARATOR);
+
+        int len = links.size();
+        int i = 0;
+
+        while (i < len - 1) {
+            LinkSpec a = links.get(i);
+            LinkSpec b = links.get(i + 1);
+            int remove = -1;
+
+            if ((a.start <= b.start) && (a.end > b.start)) {
+                if (b.end <= a.end) {
+                    remove = i + 1;
+                } else if ((a.end - a.start) > (b.end - b.start)) {
+                    remove = i + 1;
+                } else if ((a.end - a.start) < (b.end - b.start)) {
+                    remove = i;
+                }
+
+                if (remove != -1) {
+                    URLSpan span = links.get(remove).frameworkAddedSpan;
+                    if (span != null) {
+                        text.removeSpan(span);
+                    }
+                    links.remove(remove);
+                    len--;
+                    continue;
+                }
+
+            }
+
+            i++;
+        }
+    }
+
+    /**
+     * Do not create this static utility class.
+     */
+    private LinkifyCompatUtil() {}
+
+    private static class LinkSpec {
+        URLSpan frameworkAddedSpan;
+        String url;
+        int start;
+        int end;
+
+        LinkSpec() {
+        }
+    }
+}

+ 4 - 5
app/src/main/java/ch/threema/app/utils/LinkifyUtil.java

@@ -42,7 +42,6 @@ import android.widget.TextView;
 import android.widget.Toast;
 import android.widget.Toast;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.net.IDN;
 import java.net.IDN;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
@@ -61,13 +60,13 @@ import ch.threema.app.dialogs.GenericAlertDialog;
 import ch.threema.app.fragments.ComposeMessageFragment;
 import ch.threema.app.fragments.ComposeMessageFragment;
 import ch.threema.app.services.ContactService;
 import ch.threema.app.services.ContactService;
 import ch.threema.app.ui.MentionClickableSpan;
 import ch.threema.app.ui.MentionClickableSpan;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
 
 
 import static android.content.Context.CLIPBOARD_SERVICE;
 import static android.content.Context.CLIPBOARD_SERVICE;
 
 
-
 public class LinkifyUtil {
 public class LinkifyUtil {
-	private static final Logger logger = LoggerFactory.getLogger(LinkifyUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("LinkifyUtil");
 	public static final String DIALOG_TAG_CONFIRM_LINK = "cnfl";
 	public static final String DIALOG_TAG_CONFIRM_LINK = "cnfl";
 	private final Pattern compose, add, license;
 	private final Pattern compose, add, license;
 	private GestureDetectorCompat gestureDetector;
 	private GestureDetectorCompat gestureDetector;
@@ -141,9 +140,9 @@ public class LinkifyUtil {
 		// do not linkify phone numbers in longer texts because things can get messy on samsung devices
 		// do not linkify phone numbers in longer texts because things can get messy on samsung devices
 		// which linkify every kind of number combination imaginable
 		// which linkify every kind of number combination imaginable
 		if (includePhoneNumbers) {
 		if (includePhoneNumbers) {
-			LinkifyCompat.addLinks(bodyTextView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS);
+			LinkifyCompatUtil.addLinks(bodyTextView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS);
 		} else {
 		} else {
-			LinkifyCompat.addLinks(bodyTextView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES);
+			LinkifyCompatUtil.addLinks(bodyTextView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES);
 		}
 		}
 		LinkifyCompat.addLinks(bodyTextView, this.add, null);
 		LinkifyCompat.addLinks(bodyTextView, this.add, null);
 		LinkifyCompat.addLinks(bodyTextView, this.compose, null);
 		LinkifyCompat.addLinks(bodyTextView, this.compose, null);

+ 2 - 2
app/src/main/java/ch/threema/app/utils/LoadingUtil.java

@@ -22,13 +22,13 @@
 package ch.threema.app.utils;
 package ch.threema.app.utils;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import androidx.fragment.app.FragmentManager;
 import androidx.fragment.app.FragmentManager;
 import ch.threema.app.dialogs.GenericProgressDialog;
 import ch.threema.app.dialogs.GenericProgressDialog;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class LoadingUtil {
 public class LoadingUtil {
-	private static final Logger logger = LoggerFactory.getLogger(LocaleUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("LocaleUtil");
 
 
 	private static String DIALOG_TAG_PROGRESS_LOADINGUTIL = "lou";
 	private static String DIALOG_TAG_PROGRESS_LOADINGUTIL = "lou";
 
 

+ 0 - 5
app/src/main/java/ch/threema/app/utils/LocationUtil.java

@@ -29,9 +29,6 @@ import android.graphics.drawable.Drawable;
 import com.mapbox.mapboxsdk.annotations.Icon;
 import com.mapbox.mapboxsdk.annotations.Icon;
 import com.mapbox.mapboxsdk.annotations.IconFactory;
 import com.mapbox.mapboxsdk.annotations.IconFactory;
 
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.appcompat.content.res.AppCompatResources;
 import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.core.graphics.drawable.DrawableCompat;
@@ -41,8 +38,6 @@ import ch.threema.app.locationpicker.Poi;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.PreferenceService;
 
 
 public class LocationUtil {
 public class LocationUtil {
-	private static final Logger logger = LoggerFactory.getLogger(LocationUtil.class);
-
 	public static int getPlaceDrawableRes(@NonNull Context context, @NonNull Poi poi, boolean returnDefault) {
 	public static int getPlaceDrawableRes(@NonNull Context context, @NonNull Poi poi, boolean returnDefault) {
 		int id = 0;
 		int id = 0;
 		String defPackage = context.getPackageName();
 		String defPackage = context.getPackageName();

+ 2 - 2
app/src/main/java/ch/threema/app/utils/LogUtil.java

@@ -22,16 +22,16 @@
 package ch.threema.app.utils;
 package ch.threema.app.utils;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.slf4j.Marker;
 import org.slf4j.Marker;
 
 
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentActivity;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.dialogs.SimpleStringAlertDialog;
 import ch.threema.app.dialogs.SimpleStringAlertDialog;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class LogUtil {
 public class LogUtil {
-	private static final Logger logger = LoggerFactory.getLogger(LogUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("LogUtil");
 
 
 	private LogUtil() { }
 	private LogUtil() { }
 
 

+ 3 - 2
app/src/main/java/ch/threema/app/utils/LoggingUEH.java

@@ -24,10 +24,11 @@ package ch.threema.app.utils;
 import android.content.Context;
 import android.content.Context;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class LoggingUEH implements Thread.UncaughtExceptionHandler {
 public class LoggingUEH implements Thread.UncaughtExceptionHandler {
-	private static final Logger logger = LoggerFactory.getLogger(LoggingUEH.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("LoggingUEH");
 
 
 	private final Thread.UncaughtExceptionHandler defaultUEH;
 	private final Thread.UncaughtExceptionHandler defaultUEH;
 	private Context context;
 	private Context context;

+ 2 - 2
app/src/main/java/ch/threema/app/utils/MediaPlayerStateWrapper.java

@@ -30,12 +30,12 @@ import android.net.Uri;
 import android.os.Build;
 import android.os.Build;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.IOException;
 import java.io.IOException;
 import java.util.EnumSet;
 import java.util.EnumSet;
 
 
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RequiresApi;
+import ch.threema.base.utils.LoggingUtil;
 
 
 /**
 /**
  * A wrapper class for {@link android.media.MediaPlayer}.
  * A wrapper class for {@link android.media.MediaPlayer}.
@@ -45,7 +45,7 @@ import androidx.annotation.RequiresApi;
  * </p>
  * </p>
  */
  */
 public class MediaPlayerStateWrapper {
 public class MediaPlayerStateWrapper {
-	private static final Logger logger = LoggerFactory.getLogger(MediaPlayerStateWrapper.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("MediaPlayerStateWrapper");
 
 
 	private MediaPlayer mediaPlayer;
 	private MediaPlayer mediaPlayer;
 	private State currentState;
 	private State currentState;

+ 2 - 2
app/src/main/java/ch/threema/app/utils/MessageUtil.java

@@ -24,7 +24,6 @@ package ch.threema.app.utils;
 import android.content.Context;
 import android.content.Context;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Date;
@@ -40,6 +39,7 @@ import ch.threema.app.R;
 import ch.threema.app.collections.Functional;
 import ch.threema.app.collections.Functional;
 import ch.threema.app.collections.IPredicateNonNull;
 import ch.threema.app.collections.IPredicateNonNull;
 import ch.threema.app.messagereceiver.MessageReceiver;
 import ch.threema.app.messagereceiver.MessageReceiver;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.domain.protocol.csp.ProtocolDefines;
 import ch.threema.domain.protocol.csp.ProtocolDefines;
 import ch.threema.domain.protocol.csp.messages.file.FileData;
 import ch.threema.domain.protocol.csp.messages.file.FileData;
 import ch.threema.domain.protocol.csp.messages.voip.VoipCallAnswerData;
 import ch.threema.domain.protocol.csp.messages.voip.VoipCallAnswerData;
@@ -53,7 +53,7 @@ import ch.threema.storage.models.data.MessageContentsType;
 import ch.threema.storage.models.data.status.VoipStatusDataModel;
 import ch.threema.storage.models.data.status.VoipStatusDataModel;
 
 
 public class MessageUtil {
 public class MessageUtil {
-	private static final Logger logger = LoggerFactory.getLogger(MessageUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("MessageUtil");
 
 
 	private final static java.util.Set<MessageType> fileMessageModelTypes = EnumSet.of(
 	private final static java.util.Set<MessageType> fileMessageModelTypes = EnumSet.of(
 			MessageType.IMAGE,
 			MessageType.IMAGE,

+ 2 - 2
app/src/main/java/ch/threema/app/utils/NavigationUtil.java

@@ -25,16 +25,16 @@ import android.app.Activity;
 import android.content.Intent;
 import android.content.Intent;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.core.app.NavUtils;
 import androidx.core.app.NavUtils;
 import androidx.core.app.TaskStackBuilder;
 import androidx.core.app.TaskStackBuilder;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.activities.PinLockActivity;
 import ch.threema.app.activities.PinLockActivity;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class NavigationUtil {
 public class NavigationUtil {
-	private static final Logger logger = LoggerFactory.getLogger(NavigationUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("NavigationUtil");
 
 
 	public static void navigateUpToHome(@NonNull Activity activity) {
 	public static void navigateUpToHome(@NonNull Activity activity) {
 		// navigate to home and get rid of the backstack (since we may have pulled the rug from under our feet)
 		// navigate to home and get rid of the backstack (since we may have pulled the rug from under our feet)

+ 2 - 2
app/src/main/java/ch/threema/app/utils/PowermanagerUtil.java

@@ -28,16 +28,16 @@ import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ResolveInfo;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.List;
 import java.util.List;
 
 
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.Fragment;
 import ch.threema.app.activities.DisableBatteryOptimizationsActivity;
 import ch.threema.app.activities.DisableBatteryOptimizationsActivity;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class PowermanagerUtil {
 public class PowermanagerUtil {
-	private static final Logger logger = LoggerFactory.getLogger(PowermanagerUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("PowermanagerUtil");
 
 
 	// https://stackoverflow.com/questions/48166206/how-to-start-power-manager-of-all-android-manufactures-to-enable-push-notificati/48166241
 	// https://stackoverflow.com/questions/48166206/how-to-start-power-manager-of-all-android-manufactures-to-enable-push-notificati/48166241
 	// https://stackoverflow.com/questions/31638986/protected-apps-setting-on-huawei-phones-and-how-to-handle-it
 	// https://stackoverflow.com/questions/31638986/protected-apps-setting-on-huawei-phones-and-how-to-handle-it

+ 2 - 2
app/src/main/java/ch/threema/app/utils/PushUtil.java

@@ -33,7 +33,6 @@ import android.net.Uri;
 import android.text.format.DateUtils;
 import android.text.format.DateUtils;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.Map;
 import java.util.Map;
 
 
@@ -63,10 +62,11 @@ import ch.threema.app.services.RingtoneService;
 import ch.threema.app.stores.PreferenceStore;
 import ch.threema.app.stores.PreferenceStore;
 import ch.threema.app.webclient.services.SessionWakeUpServiceImpl;
 import ch.threema.app.webclient.services.SessionWakeUpServiceImpl;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.ThreemaException;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.domain.protocol.csp.connection.ThreemaConnection;
 import ch.threema.domain.protocol.csp.connection.ThreemaConnection;
 
 
 public class PushUtil {
 public class PushUtil {
-	private static final Logger logger = LoggerFactory.getLogger(PushUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("PushUtil");
 
 
 	public static final String EXTRA_CLEAR_TOKEN = "clear";
 	public static final String EXTRA_CLEAR_TOKEN = "clear";
 	public static final String EXTRA_WITH_CALLBACK = "cb";
 	public static final String EXTRA_WITH_CALLBACK = "cb";

+ 2 - 2
app/src/main/java/ch/threema/app/utils/QRScannerUtil.java

@@ -26,7 +26,6 @@ import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.app.AppCompatActivity;
@@ -36,9 +35,10 @@ import ch.threema.app.dialogs.SimpleStringAlertDialog;
 import ch.threema.app.qrscanner.activity.BaseQrScannerActivity;
 import ch.threema.app.qrscanner.activity.BaseQrScannerActivity;
 import ch.threema.app.qrscanner.activity.CaptureActivity;
 import ch.threema.app.qrscanner.activity.CaptureActivity;
 import ch.threema.app.services.QRCodeService;
 import ch.threema.app.services.QRCodeService;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class QRScannerUtil {
 public class QRScannerUtil {
-	private static final Logger logger = LoggerFactory.getLogger(QRScannerUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("QRScannerUtil");
 
 
 	private static boolean scanAnyCode;
 	private static boolean scanAnyCode;
 	public static final int REQUEST_CODE_QR_SCANNER = 26657;
 	public static final int REQUEST_CODE_QR_SCANNER = 26657;

+ 2 - 2
app/src/main/java/ch/threema/app/utils/QuoteUtil.java

@@ -26,7 +26,6 @@ import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.regex.Matcher;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
@@ -41,6 +40,7 @@ import ch.threema.app.messagereceiver.MessageReceiver.MessageReceiverType;
 import ch.threema.app.services.FileService;
 import ch.threema.app.services.FileService;
 import ch.threema.app.services.MessageService;
 import ch.threema.app.services.MessageService;
 import ch.threema.app.services.UserService;
 import ch.threema.app.services.UserService;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.base.utils.Utils;
 import ch.threema.base.utils.Utils;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.DistributionListMessageModel;
 import ch.threema.storage.models.DistributionListMessageModel;
@@ -52,7 +52,7 @@ import static ch.threema.app.messagereceiver.MessageReceiver.Type_DISTRIBUTION_L
 import static ch.threema.app.messagereceiver.MessageReceiver.Type_GROUP;
 import static ch.threema.app.messagereceiver.MessageReceiver.Type_GROUP;
 
 
 public class QuoteUtil {
 public class QuoteUtil {
-	private static final Logger logger = LoggerFactory.getLogger(QuoteUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("QuoteUtil");
 
 
 	private static final Pattern bodyMatchPattern = Pattern.compile("(?sm)(\\A> .*?)^(?!> ).+");
 	private static final Pattern bodyMatchPattern = Pattern.compile("(?sm)(\\A> .*?)^(?!> ).+");
 	private static final Pattern quoteV1MatchPattern = Pattern.compile("(?sm)\\A> ([A-Z0-9*]{8}): (.*?)^(?!> ).+");
 	private static final Pattern quoteV1MatchPattern = Pattern.compile("(?sm)\\A> ([A-Z0-9*]{8}): (.*?)^(?!> ).+");

+ 3 - 2
app/src/main/java/ch/threema/app/utils/SecureDeleteUtil.java

@@ -22,14 +22,15 @@
 package ch.threema.app.utils;
 package ch.threema.app.utils;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.io.RandomAccessFile;
 
 
+import ch.threema.base.utils.LoggingUtil;
+
 public class SecureDeleteUtil {
 public class SecureDeleteUtil {
-	private static final Logger logger = LoggerFactory.getLogger(SecureDeleteUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("SecureDeleteUtil");
 
 
     public static void secureDelete(File file) throws IOException {
     public static void secureDelete(File file) throws IOException {
         if (file != null && file.exists()) {
         if (file != null && file.exists()) {

+ 2 - 2
app/src/main/java/ch/threema/app/utils/ShortcutUtil.java

@@ -33,7 +33,6 @@ import android.os.SystemClock;
 import android.widget.Toast;
 import android.widget.Toast;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
@@ -64,6 +63,7 @@ import ch.threema.app.services.ConversationService;
 import ch.threema.app.voip.activities.CallActivity;
 import ch.threema.app.voip.activities.CallActivity;
 import ch.threema.app.voip.services.VoipCallService;
 import ch.threema.app.voip.services.VoipCallService;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.ThreemaException;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.AbstractMessageModel;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ContactModel;
 import ch.threema.storage.models.ConversationModel;
 import ch.threema.storage.models.ConversationModel;
@@ -71,7 +71,7 @@ import ch.threema.storage.models.ConversationModel;
 import static androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_PINNED;
 import static androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_PINNED;
 
 
 public final class ShortcutUtil {
 public final class ShortcutUtil {
-	private static final Logger logger = LoggerFactory.getLogger(ShortcutUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("ShortcutUtil");
 
 
 	private static final int MAX_SHARE_TARGETS = 100; // we recommend that you publish only four distinct shortcuts to improve their visual appearance in the launcher. https://developer.android.com/guide/topics/ui/shortcuts/best-practices
 	private static final int MAX_SHARE_TARGETS = 100; // we recommend that you publish only four distinct shortcuts to improve their visual appearance in the launcher. https://developer.android.com/guide/topics/ui/shortcuts/best-practices
 
 

+ 2 - 2
app/src/main/java/ch/threema/app/utils/StreamUtil.java

@@ -26,7 +26,6 @@ import android.content.Context;
 import android.net.Uri;
 import android.net.Uri;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileInputStream;
@@ -34,9 +33,10 @@ import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.InputStream;
 
 
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class StreamUtil {
 public class StreamUtil {
-	private static final Logger logger = LoggerFactory.getLogger(StreamUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("StreamUtil");
 
 
 	public static InputStream getFromUri(Context context, Uri uri) throws FileNotFoundException {
 	public static InputStream getFromUri(Context context, Uri uri) throws FileNotFoundException {
 		InputStream inputStream = null;
 		InputStream inputStream = null;

+ 2 - 2
app/src/main/java/ch/threema/app/utils/SynchronizeContactsUtil.java

@@ -26,7 +26,6 @@ import android.os.Bundle;
 import android.os.UserManager;
 import android.os.UserManager;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.exceptions.FileSystemNotPresentException;
 import ch.threema.app.exceptions.FileSystemNotPresentException;
@@ -34,10 +33,11 @@ import ch.threema.app.managers.ServiceManager;
 import ch.threema.app.routines.SynchronizeContactsRoutine;
 import ch.threema.app.routines.SynchronizeContactsRoutine;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.PreferenceService;
 import ch.threema.app.services.SynchronizeContactsService;
 import ch.threema.app.services.SynchronizeContactsService;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.localcrypto.MasterKeyLockedException;
 import ch.threema.localcrypto.MasterKeyLockedException;
 
 
 public class SynchronizeContactsUtil {
 public class SynchronizeContactsUtil {
-	private static final Logger logger = LoggerFactory.getLogger(SynchronizeContactsUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("SynchronizeContactsUtil");
 
 
 	public static void startDirectly() {
 	public static void startDirectly() {
 		SynchronizeContactsRoutine routine = getSynchronizeContactsRoutine();
 		SynchronizeContactsRoutine routine = getSynchronizeContactsRoutine();

+ 2 - 2
app/src/main/java/ch/threema/app/utils/TextUtil.java

@@ -29,7 +29,6 @@ import android.text.style.BackgroundColorSpan;
 import android.text.style.ForegroundColorSpan;
 import android.text.style.ForegroundColorSpan;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.io.BufferedReader;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.IOException;
@@ -42,9 +41,10 @@ import androidx.annotation.NonNull;
 import androidx.annotation.WorkerThread;
 import androidx.annotation.WorkerThread;
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.emojis.EmojiParser;
 import ch.threema.app.emojis.EmojiParser;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class TextUtil {
 public class TextUtil {
-	private static final Logger logger = LoggerFactory.getLogger(TextUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("TextUtil");
 
 
 	public static String trim(String string, int maxLength, String postFix) {
 	public static String trim(String string, int maxLength, String postFix) {
 		if ((maxLength > 0) && (string.length() > maxLength)) {
 		if ((maxLength > 0) && (string.length() > maxLength)) {

+ 2 - 2
app/src/main/java/ch/threema/app/utils/TurnServerCache.java

@@ -22,18 +22,18 @@
 package ch.threema.app.utils;
 package ch.threema.app.utils;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import java.util.Date;
 import java.util.Date;
 
 
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
 import ch.threema.app.ThreemaApplication;
 import ch.threema.app.ThreemaApplication;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.domain.protocol.api.APIConnector;
 import ch.threema.domain.protocol.api.APIConnector;
 import ch.threema.logging.ThreemaLogger;
 import ch.threema.logging.ThreemaLogger;
 
 
 public class TurnServerCache {
 public class TurnServerCache {
 	// Logger
 	// Logger
-	private final Logger logger = LoggerFactory.getLogger(TurnServerCache.class);
+	private final Logger logger = LoggingUtil.getThreemaLogger("TurnServerCache");
 
 
 	private final String type;
 	private final String type;
 	private final int minSpareValidity;
 	private final int minSpareValidity;

+ 3 - 2
app/src/main/java/ch/threema/app/utils/VideoUtil.java

@@ -29,10 +29,11 @@ import android.net.Uri;
 import android.provider.MediaStore;
 import android.provider.MediaStore;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class VideoUtil {
 public class VideoUtil {
-	private static final Logger logger = LoggerFactory.getLogger(VideoUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("VideoUtil");
 
 
 	/**
 	/**
 	 * Get duration of a video represented by uri in Milliseconds
 	 * Get duration of a video represented by uri in Milliseconds

+ 2 - 2
app/src/main/java/ch/threema/app/utils/WebRTCUtil.java

@@ -24,19 +24,19 @@ package ch.threema.app.utils;
 import android.content.Context;
 import android.content.Context;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.webrtc.IceCandidate;
 import org.webrtc.IceCandidate;
 import org.webrtc.Logging;
 import org.webrtc.Logging;
 import org.webrtc.PeerConnectionFactory;
 import org.webrtc.PeerConnectionFactory;
 
 
 import androidx.annotation.NonNull;
 import androidx.annotation.NonNull;
+import ch.threema.base.utils.LoggingUtil;
 import ch.threema.logging.WebRTCLoggable;
 import ch.threema.logging.WebRTCLoggable;
 
 
 /**
 /**
  * This util handles WebRTC initialization.
  * This util handles WebRTC initialization.
  */
  */
 public class WebRTCUtil {
 public class WebRTCUtil {
-	private static final Logger logger = LoggerFactory.getLogger(WebRTCUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("WebRTCUtil");
 
 
 	private static boolean initialized = false;
 	private static boolean initialized = false;
 
 

+ 2 - 2
app/src/main/java/ch/threema/app/utils/WidgetUtil.java

@@ -26,13 +26,13 @@ import android.content.ComponentName;
 import android.content.Context;
 import android.content.Context;
 
 
 import org.slf4j.Logger;
 import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 
 import ch.threema.app.R;
 import ch.threema.app.R;
 import ch.threema.app.receivers.WidgetProvider;
 import ch.threema.app.receivers.WidgetProvider;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class WidgetUtil {
 public class WidgetUtil {
-	private static final Logger logger = LoggerFactory.getLogger(WidgetUtil.class);
+	private static final Logger logger = LoggingUtil.getThreemaLogger("WidgetUtil");
 
 
 	public static void updateWidgets(Context context) {
 	public static void updateWidgets(Context context) {
 		logger.debug("Update Widgets");
 		logger.debug("Update Widgets");

+ 6 - 0
app/src/main/java/ch/threema/app/voip/receivers/CallRejectReceiver.java

@@ -25,11 +25,17 @@ import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Context;
 import android.content.Intent;
 import android.content.Intent;
 
 
+import org.slf4j.Logger;
+
 import ch.threema.app.voip.services.CallRejectService;
 import ch.threema.app.voip.services.CallRejectService;
+import ch.threema.base.utils.LoggingUtil;
 
 
 public class CallRejectReceiver extends BroadcastReceiver {
 public class CallRejectReceiver extends BroadcastReceiver {
+	private static final Logger logger = LoggingUtil.getThreemaLogger("CallRejectReceiver");
+
 	@Override
 	@Override
 	public void onReceive(Context context, Intent intent) {
 	public void onReceive(Context context, Intent intent) {
+		logger.info("onReceive");
 		CallRejectService.enqueueWork(context, intent);
 		CallRejectService.enqueueWork(context, intent);
 	}
 	}
 }
 }

+ 2 - 2
app/src/main/java/ch/threema/app/voip/services/CallRejectService.java

@@ -54,13 +54,13 @@ public class CallRejectService extends FixedJobIntentService {
 	public static final int JOB_ID = 344339;
 	public static final int JOB_ID = 344339;
 
 
 	public static void enqueueWork(Context context, Intent work) {
 	public static void enqueueWork(Context context, Intent work) {
-		logger.debug("enqueWork entered");
+		logger.info("enqueueWork");
 		enqueueWork(context, CallRejectService.class, JOB_ID, work);
 		enqueueWork(context, CallRejectService.class, JOB_ID, work);
 	}
 	}
 
 
 	@Override
 	@Override
 	protected void onHandleWork(@NonNull Intent intent) {
 	protected void onHandleWork(@NonNull Intent intent) {
-		logger.debug("CallRejectService onHandle work");
+		logger.info("onHandleWork");
 
 
 		// Intent parameters
 		// Intent parameters
 		final String contactIdentity = intent.getStringExtra(EXTRA_CONTACT_IDENTITY);
 		final String contactIdentity = intent.getStringExtra(EXTRA_CONTACT_IDENTITY);

+ 10 - 0
app/src/main/res/drawable/ic_places_free_flying.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="#000"
+        android:pathData="M12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2s2,0.9 2,2S13.1,17 12,17zM8.52,17.94C8.04,17.55 7,16.76 7,14H5c0,2.7 0.93,4.41 2.3,5.5c0.5,0.4 1.1,0.7 1.7,0.9L9,24h6v-3.6c0.6,-0.2 1.2,-0.5 1.7,-0.9c1.37,-1.09 2.3,-2.8 2.3,-5.5h-2c0,2.76 -1.04,3.55 -1.52,3.94C14.68,18.54 14,19 12,19S9.32,18.54 8.52,17.94zM12,0C5.92,0 1,1.9 1,4.25v3.49C1,8.55 1.88,9 2.56,8.57C2.7,8.48 2.84,8.39 3,8.31L5,13h2l1.5,-6.28C9.6,6.58 10.78,6.5 12,6.5s2.4,0.08 3.5,0.22L17,13h2l2,-4.69c0.16,0.09 0.3,0.17 0.44,0.26C22.12,9 23,8.55 23,7.74V4.25C23,1.9 18.08,0 12,0zM5.88,11.24L4.37,7.69c0.75,-0.28 1.6,-0.52 2.53,-0.71L5.88,11.24zM18.12,11.24L17.1,6.98c0.93,0.19 1.78,0.43 2.53,0.71L18.12,11.24z"/>
+</vector>

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

@@ -41,7 +41,7 @@
 		android:id="@+id/disabled_by_policy"
 		android:id="@+id/disabled_by_policy"
 		android:layout_width="match_parent"
 		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
 		android:layout_height="wrap_content"
-		android:layout_marginTop="4dp"
+		android:layout_marginTop="32dp"
 		android:layout_below="@+id/wizard_switch_sync_contacts"
 		android:layout_below="@+id/wizard_switch_sync_contacts"
 		android:textSize="14sp"
 		android:textSize="14sp"
 		android:text="@string/disabled_by_policy"
 		android:text="@string/disabled_by_policy"

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

@@ -7,7 +7,7 @@
     <string name="webclient_created_at">Creato in: %1$s (%2$s)</string>
     <string name="webclient_created_at">Creato in: %1$s (%2$s)</string>
     <string name="webclient_active_since">Attivo da: %s</string>
     <string name="webclient_active_since">Attivo da: %s</string>
     <string name="webclient_enable">Abilita Threema Web</string>
     <string name="webclient_enable">Abilita Threema Web</string>
-    <string name="webclient_no_sessions_found">Per connetterti apri <b>https://web.threema.ch</b> nel browser del tuo PC e tocca il pulsante sotto per lo scan del codice.</string>
+    <string name="webclient_no_sessions_found">Per connetterti apri <b>%s</b> nel browser del tuo PC e tocca il pulsante sotto per lo scan del codice.</string>
     <string name="webclient_session_rename">Rinomina sessione</string>
     <string name="webclient_session_rename">Rinomina sessione</string>
     <string name="webclient_session_label">Nuovo nome</string>
     <string name="webclient_session_label">Nuovo nome</string>
     <string name="webclient_session_start">Avvia sessione</string>
     <string name="webclient_session_start">Avvia sessione</string>

+ 3 - 0
app/src/onprem/res/values-de/strings.xml

@@ -23,6 +23,9 @@
 		automatisch zu finden, wenn Sie in deren Adressbuch eingetragen sind. Die Angaben werden dazu in einwegverschlüsselter (gehashter) Form
 		automatisch zu finden, wenn Sie in deren Adressbuch eingetragen sind. Die Angaben werden dazu in einwegverschlüsselter (gehashter) Form
 		auf unserem Server gespeichert. Sie können diesen Schritt auch einfach übespringen, wenn Sie Threema OnPrem anonym benutzen möchten.
 		auf unserem Server gespeichert. Sie können diesen Schritt auch einfach übespringen, wenn Sie Threema OnPrem anonym benutzen möchten.
 	</string>
 	</string>
+	<string name="new_wizard_info_sync_contacts">Wenn Sie diese Option aktivieren, werden E-Mail-Adressen und Telefonnummern aus Ihrem Adressbuch einwegverschlüsselt (gehasht), bevor sie zum
+		Kontaktabgleich an der Server geschickt werden. Adressbuchdaten werden nicht auf dem Server gespeichert.
+	</string>
 	<string name="threema_contact">Threema OnPrem-Kontakt</string>
 	<string name="threema_contact">Threema OnPrem-Kontakt</string>
 	<string name="menu_about">Über Threema OnPrem</string>
 	<string name="menu_about">Über Threema OnPrem</string>
 	<string name="list_theme_light">Hell</string>
 	<string name="list_theme_light">Hell</string>

+ 2 - 0
app/src/onprem/res/values/strings.xml

@@ -23,6 +23,8 @@
 		one-way encrypted (hashed) form on our server. You can simply skip this step, if you would like to use Threema OnPrem
 		one-way encrypted (hashed) form on our server. You can simply skip this step, if you would like to use Threema OnPrem
 		anonymously.
 		anonymously.
 	</string>
 	</string>
+	<string name="new_wizard_info_sync_contacts">If you enable this option, Threema OnPrem one-way encrypts (hashes) email addresses and phone numbers
+		before sending them to the server to look for matching contacts. The data is kept in memory only and never stored on the server.</string>
 	<string name="threema_contact">Threema OnPrem Contact</string>
 	<string name="threema_contact">Threema OnPrem Contact</string>
 	<string name="menu_about">About Threema OnPrem</string>
 	<string name="menu_about">About Threema OnPrem</string>
 	<string name="list_theme_light">Light</string>
 	<string name="list_theme_light">Light</string>

+ 2 - 2
build.gradle

@@ -9,8 +9,8 @@ buildscript {
     }
     }
     dependencies {
     dependencies {
         classpath 'com.android.tools.build:gradle:4.1.3'
         classpath 'com.android.tools.build:gradle:4.1.3'
-        classpath 'org.owasp:dependency-check-gradle:6.1.6'
-        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.16'
+        classpath 'org.owasp:dependency-check-gradle:6.5.3'
+        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.18'
 
 
         // Huawei agconnect plugin
         // Huawei agconnect plugin
         classpath 'com.huawei.agconnect:agcp-1.4.2.300'
         classpath 'com.huawei.agconnect:agcp-1.4.2.300'

+ 2 - 2
domain/build.gradle

@@ -36,7 +36,7 @@ dependencies {
     api 'androidx.annotation:annotation:1.3.0'
     api 'androidx.annotation:annotation:1.3.0'
     api 'net.sourceforge.streamsupport:streamsupport-flow:1.7.0'
     api 'net.sourceforge.streamsupport:streamsupport-flow:1.7.0'
 
 
-    api 'com.google.protobuf:protobuf-javalite:3.11.4'
+    api 'com.google.protobuf:protobuf-javalite:3.19.4'
 
 
     implementation "org.slf4j:slf4j-api:$slf4j_version"
     implementation "org.slf4j:slf4j-api:$slf4j_version"
     // commons-io >2.6 requires android 8
     // commons-io >2.6 requires android 8
@@ -61,7 +61,7 @@ sourceCompatibility = '1.8'
 
 
 protobuf {
 protobuf {
     protoc {
     protoc {
-        artifact = 'com.google.protobuf:protoc:3.16.0'
+        artifact = 'com.google.protobuf:protoc:3.19.4'
     }
     }
     generateProtoTasks {
     generateProtoTasks {
         all().each { task ->
         all().each { task ->

+ 6 - 4
domain/src/main/java/ch/threema/domain/onprem/OnPremConfig.java

@@ -21,6 +21,8 @@
 
 
 package ch.threema.domain.onprem;
 package ch.threema.domain.onprem;
 
 
+import androidx.annotation.Nullable;
+
 public class OnPremConfig {
 public class OnPremConfig {
 
 
 	private final int refresh;
 	private final int refresh;
@@ -42,8 +44,8 @@ public class OnPremConfig {
 	                    OnPremConfigWork workConfig,
 	                    OnPremConfigWork workConfig,
 	                    OnPremConfigAvatar avatarConfig,
 	                    OnPremConfigAvatar avatarConfig,
 	                    OnPremConfigSafe safeConfig,
 	                    OnPremConfigSafe safeConfig,
-	                    OnPremConfigWeb webConfig,
-	                    OnPremConfigMediator mediatorConfig) {
+	                    @Nullable OnPremConfigWeb webConfig,
+	                    @Nullable OnPremConfigMediator mediatorConfig) {
 		this.refresh = refresh;
 		this.refresh = refresh;
 		this.chatConfig = chatConfig;
 		this.chatConfig = chatConfig;
 		this.license = license;
 		this.license = license;
@@ -88,11 +90,11 @@ public class OnPremConfig {
 		return safeConfig;
 		return safeConfig;
 	}
 	}
 
 
-	public OnPremConfigWeb getWebConfig() {
+	public @Nullable OnPremConfigWeb getWebConfig() {
 		return webConfig;
 		return webConfig;
 	}
 	}
 
 
-	public OnPremConfigMediator getMediatorConfig() {
+	public @Nullable OnPremConfigMediator getMediatorConfig() {
 		return mediatorConfig;
 		return mediatorConfig;
 	}
 	}
 }
 }

+ 8 - 5
domain/src/main/java/ch/threema/domain/onprem/OnPremConfigParser.java

@@ -44,7 +44,7 @@ public class OnPremConfigParser {
 			this.parseWorkConfig(obj.getJSONObject("work")),
 			this.parseWorkConfig(obj.getJSONObject("work")),
 			this.parseAvatarConfig(obj.getJSONObject("avatar")),
 			this.parseAvatarConfig(obj.getJSONObject("avatar")),
 			this.parseSafeConfig(obj.getJSONObject("safe")),
 			this.parseSafeConfig(obj.getJSONObject("safe")),
-			this.parseWebConfig(obj.getJSONObject("web")),
+			this.parseWebConfig(obj.optJSONObject("web")),
 			this.parseMediatorConfig(obj.optJSONObject("mediator")));
 			this.parseMediatorConfig(obj.optJSONObject("mediator")));
 	}
 	}
 
 
@@ -88,14 +88,17 @@ public class OnPremConfigParser {
 		return new OnPremConfigSafe(obj.getString("url"));
 		return new OnPremConfigSafe(obj.getString("url"));
 	}
 	}
 
 
-	private OnPremConfigWeb parseWebConfig(JSONObject obj) throws JSONException {
-		return new OnPremConfigWeb(obj.getString("url"));
-	}
-
 	private OnPremConfigWork parseWorkConfig(JSONObject obj) throws JSONException {
 	private OnPremConfigWork parseWorkConfig(JSONObject obj) throws JSONException {
 		return new OnPremConfigWork(obj.getString("url"));
 		return new OnPremConfigWork(obj.getString("url"));
 	}
 	}
 
 
+	private OnPremConfigWeb parseWebConfig(JSONObject obj) throws JSONException {
+		if (obj == null) {
+			return null;
+		}
+		return new OnPremConfigWeb(obj.getString("url"));
+	}
+
 	private OnPremConfigMediator parseMediatorConfig(JSONObject obj) throws JSONException {
 	private OnPremConfigMediator parseMediatorConfig(JSONObject obj) throws JSONException {
 		if (obj == null) {
 		if (obj == null) {
 			return null;
 			return null;

+ 8 - 1
domain/src/main/java/ch/threema/domain/onprem/ServerAddressProviderOnPrem.java

@@ -21,6 +21,7 @@
 
 
 package ch.threema.domain.onprem;
 package ch.threema.domain.onprem;
 
 
+import androidx.annotation.Nullable;
 import ch.threema.base.ThreemaException;
 import ch.threema.base.ThreemaException;
 import ch.threema.domain.protocol.ServerAddressProvider;
 import ch.threema.domain.protocol.ServerAddressProvider;
 
 
@@ -103,8 +104,14 @@ public class ServerAddressProviderOnPrem implements ServerAddressProvider {
 	}
 	}
 
 
 	@Override
 	@Override
+	@Nullable
 	public String getWebServerUrl() throws ThreemaException {
 	public String getWebServerUrl() throws ThreemaException {
-		return getOnPremConfigFetcher().fetch().getWebConfig().getUrl();
+		OnPremConfigWeb onPremConfigWeb = getOnPremConfigFetcher().fetch().getWebConfig();
+
+		if (onPremConfigWeb != null) {
+			return onPremConfigWeb.getUrl();
+		}
+		throw new ThreemaException("Unable to fetch Threema Web server url");
 	}
 	}
 
 
 	private OnPremConfigFetcher getOnPremConfigFetcher() throws ThreemaException {
 	private OnPremConfigFetcher getOnPremConfigFetcher() throws ThreemaException {

+ 9 - 4
domain/src/main/java/ch/threema/domain/protocol/csp/coders/MessageCoder.java

@@ -260,11 +260,16 @@ public class MessageCoder {
 					locationmsg.setAccuracy(Double.parseDouble(locArr[2]));
 					locationmsg.setAccuracy(Double.parseDouble(locArr[2]));
 				}
 				}
 
 
-				if (lines.length >= 2) {
+				String address = null;
+				if (lines.length == 2) {
+					address = lines[1];
+				} else if (lines.length >= 3) {
 					locationmsg.setPoiName(lines[1]);
 					locationmsg.setPoiName(lines[1]);
-					if (lines.length >= 3) {
-						locationmsg.setPoiAddress(lines[2].replace("\\n", "\n"));
-					}
+					address = lines[2];
+				}
+
+				if (address != null) {
+					locationmsg.setPoiAddress(address.replace("\\n", "\n"));
 				}
 				}
 
 
 				if (locationmsg.getLatitude() < -90.0 || locationmsg.getLatitude() > 90.0 ||
 				if (locationmsg.getLatitude() < -90.0 || locationmsg.getLatitude() > 90.0 ||

+ 1 - 1
gradle.properties

@@ -19,7 +19,7 @@
 
 
 #android.useDeprecatedNdk=true
 #android.useDeprecatedNdk=true
 manifestmerger.enabled=true
 manifestmerger.enabled=true
-org.gradle.jvmargs=-Xmx4096M
+org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8
 org.gradle.caching=true
 org.gradle.caching=true
 android.useAndroidX=true
 android.useAndroidX=true
 android.enableJetifier=true
 android.enableJetifier=true