From 9138a8972f3ede9a0ca7ca9a7aa104a8cd8ad6b4 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Wed, 5 Nov 2025 10:09:50 -0500 Subject: [PATCH] Convert LogSectionSystemInfo to kotlin. --- .../logsubmit/LogSectionSystemInfo.java | 213 ------------------ .../logsubmit/LogSectionSystemInfo.kt | 187 +++++++++++++++ 2 files changed, 187 insertions(+), 213 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java create mode 100644 app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java deleted file mode 100644 index 54a18f62da..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java +++ /dev/null @@ -1,213 +0,0 @@ -package org.thoughtcrime.securesms.logsubmit; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.Build; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.view.WindowManager; - -import androidx.annotation.NonNull; - -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GoogleApiAvailability; - -import org.signal.core.util.FontUtil; -import org.thoughtcrime.securesms.BuildConfig; -import org.thoughtcrime.securesms.dependencies.AppDependencies; -import org.thoughtcrime.securesms.emoji.EmojiFiles; -import org.thoughtcrime.securesms.keyvalue.SignalStore; -import org.thoughtcrime.securesms.net.StandardUserAgentInterceptor; -import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.service.webrtc.AndroidTelecomUtil; -import org.thoughtcrime.securesms.util.AppSignatureUtil; -import org.thoughtcrime.securesms.util.ByteUnit; -import org.thoughtcrime.securesms.util.ContextUtil; -import org.thoughtcrime.securesms.util.DeviceProperties; -import org.thoughtcrime.securesms.util.NetworkUtil; -import org.thoughtcrime.securesms.util.PowerManagerCompat; -import org.thoughtcrime.securesms.util.ScreenDensity; -import org.thoughtcrime.securesms.util.ServiceUtil; -import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.Util; -import org.thoughtcrime.securesms.util.VersionTracker; -import org.whispersystems.signalservice.api.push.ServiceId.ACI; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.Locale; - -import static org.thoughtcrime.securesms.window.WindowSizeClassExtensionsKt.getWindowSizeClass; - -public class LogSectionSystemInfo implements LogSection { - - @Override - public @NonNull String getTitle() { - return "SYSINFO"; - } - - @Override - public @NonNull CharSequence getContent(@NonNull Context context) { - final PackageManager pm = context.getPackageManager(); - final StringBuilder builder = new StringBuilder(); - - builder.append("Time : ").append(System.currentTimeMillis()).append('\n'); - builder.append("Manufacturer : ").append(Build.MANUFACTURER).append("\n"); - builder.append("Model : ").append(Build.MODEL).append("\n"); - builder.append("Product : ").append(Build.PRODUCT).append("\n"); - builder.append("SoC Manufacturer : ").append(Build.VERSION.SDK_INT >= 31 ? Build.SOC_MANUFACTURER : "N/A").append("\n"); - builder.append("SoC Model : ").append(Build.VERSION.SDK_INT >= 31 ? Build.SOC_MODEL : "N/A").append("\n"); - builder.append("Screen : ").append(getScreenResolution(context)).append(", ") - .append(ScreenDensity.get(context)).append(", ") - .append(getScreenRefreshRate(context)).append("\n"); - builder.append("WindowSizeClass : ").append(getWindowSizeClass(context.getResources())).append("\n"); - builder.append("Font Scale : ").append(context.getResources().getConfiguration().fontScale).append("\n"); - builder.append("Animation Scale : ").append(ContextUtil.getAnimationScale(context)).append("\n"); - builder.append("Android : ").append(Build.VERSION.RELEASE).append(", API ") - .append(Build.VERSION.SDK_INT).append(" (") - .append(Build.VERSION.INCREMENTAL).append(", ") - .append(Build.DISPLAY).append(")\n"); - builder.append("ABIs : ").append(TextUtils.join(", ", getSupportedAbis())).append("\n"); - builder.append("Memory : ").append(getMemoryUsage()).append("\n"); - builder.append("Memclass : ").append(getMemoryClass(context)).append("\n"); - builder.append("MemInfo : ").append(getMemoryInfo(context)).append("\n"); - builder.append("OS Host : ").append(Build.HOST).append("\n"); - builder.append("RecipientId : ").append(SignalStore.registration().isRegistrationComplete() ? Recipient.self().getId() : "N/A").append("\n"); - builder.append("ACI : ").append(getCensoredAci(context)).append("\n"); - builder.append("Device ID : ").append(SignalStore.account().getDeviceId()).append("\n"); - builder.append("Censored : ").append(AppDependencies.getSignalServiceNetworkAccess().isCensored()).append("\n"); - builder.append("Network Status : ").append(NetworkUtil.getNetworkStatus(context)).append("\n"); - builder.append("Play Services : ").append(getPlayServicesString(context)).append("\n"); - builder.append("FCM : ").append(SignalStore.account().isFcmEnabled()).append("\n"); - builder.append("Locale : ").append(Locale.getDefault()).append("\n"); - builder.append("Linked Devices : ").append(SignalStore.account().isMultiDevice()).append("\n"); - builder.append("First Version : ").append(TextSecurePreferences.getFirstInstallVersion(context)).append("\n"); - builder.append("Days Installed : ").append(VersionTracker.getDaysSinceFirstInstalled(context)).append("\n"); - builder.append("Build Variant : ").append(BuildConfig.BUILD_DISTRIBUTION_TYPE).append(BuildConfig.BUILD_ENVIRONMENT_TYPE).append(BuildConfig.BUILD_VARIANT_TYPE).append("\n"); - builder.append("Emoji Version : ").append(getEmojiVersionString(context)).append("\n"); - builder.append("RenderBigEmoji : ").append(FontUtil.canRenderEmojiAtFontSize(1024)).append("\n"); - builder.append("DontKeepActivities: ").append(getDontKeepActivities(context)).append("\n"); - builder.append("Server Time Offset: ").append(SignalStore.misc().getLastKnownServerTimeOffset()).append(" ms (last updated: ").append(SignalStore.misc().getLastKnownServerTimeOffsetUpdateTime()).append(")").append("\n"); - builder.append("Telecom : ").append(AndroidTelecomUtil.getTelecomSupported()).append("\n"); - builder.append("User-Agent : ").append(StandardUserAgentInterceptor.USER_AGENT).append("\n"); - builder.append("SlowNotifications : ").append(SlowNotificationHeuristics.isHavingDelayedNotifications()).append("\n"); - builder.append("IgnoringBatteryOpt: ").append(PowerManagerCompat.isIgnoringBatteryOptimizations(context)).append("\n"); - builder.append("BkgRestricted : ").append(Build.VERSION.SDK_INT >= 28 ? DeviceProperties.isBackgroundRestricted(context) : "N/A").append("\n"); - builder.append("Data Saver : ").append(DeviceProperties.getDataSaverState(context)).append("\n"); - builder.append("APNG Animation : ").append(DeviceProperties.shouldAllowApngStickerAnimation(context)).append("\n"); - if (BuildConfig.MANAGES_APP_UPDATES) { - builder.append("ApkManifestUrl : ").append(BuildConfig.APK_UPDATE_MANIFEST_URL).append("\n"); - } - builder.append("App : "); - - try { - builder.append(pm.getApplicationLabel(pm.getApplicationInfo(context.getPackageName(), 0))) - .append(" ") - .append(pm.getPackageInfo(context.getPackageName(), 0).versionName) - .append(" (") - .append(BuildConfig.CANONICAL_VERSION_CODE) - .append(", ") - .append(Util.getManifestApkVersion(context)) - .append(") (") - .append(BuildConfig.GIT_HASH).append(") \n"); - } catch (PackageManager.NameNotFoundException nnfe) { - builder.append("Unknown\n"); - } - builder.append("Package : ").append(BuildConfig.APPLICATION_ID).append(" (").append(getSigningString(context)).append(")"); - - return builder; - } - - private static @NonNull String getMemoryUsage() { - Runtime info = Runtime.getRuntime(); - long totalMemory = info.totalMemory(); - - return String.format(Locale.ENGLISH, - "%dM (%.2f%% free, %dM max)", - ByteUnit.BYTES.toMegabytes(totalMemory), - (float) info.freeMemory() / totalMemory * 100f, - ByteUnit.BYTES.toMegabytes(info.maxMemory())); - } - - private static @NonNull String getMemoryClass(Context context) { - ActivityManager activityManager = ServiceUtil.getActivityManager(context); - String lowMem = ""; - - if (activityManager.isLowRamDevice()) { - lowMem = ", low-mem device"; - } - - return activityManager.getMemoryClass() + lowMem; - } - - private static @NonNull String getMemoryInfo(Context context) { - ActivityManager.MemoryInfo info = DeviceProperties.getMemoryInfo(context); - return String.format(Locale.US, "availMem: %d mb, totalMem: %d mb, threshold: %d mb, lowMemory: %b", - ByteUnit.BYTES.toMegabytes(info.availMem), ByteUnit.BYTES.toMegabytes(info.totalMem), ByteUnit.BYTES.toMegabytes(info.threshold), info.lowMemory); - } - - private static @NonNull Iterable getSupportedAbis() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return Arrays.asList(Build.SUPPORTED_ABIS); - } else { - LinkedList abis = new LinkedList<>(); - abis.add(Build.CPU_ABI); - if (Build.CPU_ABI2 != null && !"unknown".equals(Build.CPU_ABI2)) { - abis.add(Build.CPU_ABI2); - } - return abis; - } - } - - private static @NonNull String getScreenResolution(@NonNull Context context) { - DisplayMetrics displayMetrics = new DisplayMetrics(); - WindowManager windowManager = ServiceUtil.getWindowManager(context); - - windowManager.getDefaultDisplay().getMetrics(displayMetrics); - return displayMetrics.widthPixels + "x" + displayMetrics.heightPixels; - } - - private static @NonNull String getScreenRefreshRate(@NonNull Context context) { - return String.format(Locale.ENGLISH, "%.2f hz", ServiceUtil.getWindowManager(context).getDefaultDisplay().getRefreshRate()); - } - - private static String getSigningString(@NonNull Context context) { - return AppSignatureUtil.getAppSignature(context); - } - - private static String getPlayServicesString(@NonNull Context context) { - int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context); - return result == ConnectionResult.SUCCESS ? "true" : "false (" + result + ")"; - } - - private static String getEmojiVersionString(@NonNull Context context) { - EmojiFiles.Version version = EmojiFiles.Version.readVersion(context); - - if (version == null) { - return "None"; - } else { - return version.getVersion() + " (" + version.getDensity() + ")"; - } - } - - private static String getCensoredAci(@NonNull Context context) { - ACI aci = SignalStore.account().getAci(); - - if (aci != null) { - String aciString = aci.toString(); - String lastThree = aciString.substring(aciString.length() - 3); - - return "********-****-****-****-*********" + lastThree; - } else { - return "N/A"; - } - } - - private static String getDontKeepActivities(@NonNull Context context) { - int setting = Settings.Global.getInt(context.getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0); - return setting == 0 ? "false" : "true"; - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.kt b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.kt new file mode 100644 index 0000000000..9f0c1cc6a7 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.kt @@ -0,0 +1,187 @@ +package org.thoughtcrime.securesms.logsubmit + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import android.provider.Settings +import android.util.DisplayMetrics +import com.google.android.gms.common.ConnectionResult +import com.google.android.gms.common.GoogleApiAvailability +import org.signal.core.util.FontUtil.canRenderEmojiAtFontSize +import org.signal.core.util.bytes +import org.signal.core.util.roundedString +import org.thoughtcrime.securesms.BuildConfig +import org.thoughtcrime.securesms.dependencies.AppDependencies.signalServiceNetworkAccess +import org.thoughtcrime.securesms.emoji.EmojiFiles.Version.Companion.readVersion +import org.thoughtcrime.securesms.keyvalue.SignalStore.Companion.account +import org.thoughtcrime.securesms.keyvalue.SignalStore.Companion.misc +import org.thoughtcrime.securesms.keyvalue.SignalStore.Companion.registration +import org.thoughtcrime.securesms.net.StandardUserAgentInterceptor +import org.thoughtcrime.securesms.notifications.SlowNotificationHeuristics.isHavingDelayedNotifications +import org.thoughtcrime.securesms.recipients.Recipient.Companion.self +import org.thoughtcrime.securesms.service.webrtc.AndroidTelecomUtil.telecomSupported +import org.thoughtcrime.securesms.util.AppSignatureUtil +import org.thoughtcrime.securesms.util.ContextUtil +import org.thoughtcrime.securesms.util.DeviceProperties +import org.thoughtcrime.securesms.util.NetworkUtil +import org.thoughtcrime.securesms.util.PowerManagerCompat +import org.thoughtcrime.securesms.util.ScreenDensity +import org.thoughtcrime.securesms.util.ServiceUtil +import org.thoughtcrime.securesms.util.TextSecurePreferences +import org.thoughtcrime.securesms.util.Util +import org.thoughtcrime.securesms.util.VersionTracker.getDaysSinceFirstInstalled +import org.thoughtcrime.securesms.window.getWindowSizeClass +import java.util.Locale + +class LogSectionSystemInfo : LogSection { + + override fun getTitle(): String { + return "SYSINFO" + } + + override fun getContent(context: Context): CharSequence { + return """ + Time : ${System.currentTimeMillis()} + Manufacturer : ${Build.MANUFACTURER} + Model : ${Build.MODEL} + Product : ${Build.PRODUCT} + SoC Manufacturer : ${if (Build.VERSION.SDK_INT >= 31) Build.SOC_MANUFACTURER else "N/A"} + SoC Model : ${if (Build.VERSION.SDK_INT >= 31) Build.SOC_MODEL else "N/A"} + Screen : ${getScreenResolution(context)}, ${ScreenDensity.get(context)}, ${getScreenRefreshRate(context)} + WindowSizeClass : ${context.resources.getWindowSizeClass()} + Font Scale : ${context.resources.configuration.fontScale} + Animation Scale : ${ContextUtil.getAnimationScale(context)} + Android : ${Build.VERSION.RELEASE}, API ${Build.VERSION.SDK_INT} (${Build.VERSION.INCREMENTAL}, ${Build.DISPLAY}) + ABIs : ${Build.SUPPORTED_ABIS.joinToString(separator = ", ")} + Memory : ${getMemoryUsage()} + Memclass : ${getMemoryClass(context)} + MemInfo : ${getMemoryInfo(context)} + OS Host : ${Build.HOST} + RecipientId : ${if (registration.isRegistrationComplete) self().id else "N/A"} + ACI : ${getCensoredAci()} + Device ID : ${account.deviceId} + Censored : ${signalServiceNetworkAccess.isCensored()} + Network Status : ${NetworkUtil.getNetworkStatus(context)} + Play Services : ${getPlayServicesString(context)} + FCM : ${account.fcmEnabled} + Locale : ${Locale.getDefault()} + Linked Devices : ${account.isMultiDevice} + First Version : ${TextSecurePreferences.getFirstInstallVersion(context)} + Days Installed : ${getDaysSinceFirstInstalled(context)} + Build Variant : ${BuildConfig.BUILD_DISTRIBUTION_TYPE}${BuildConfig.BUILD_ENVIRONMENT_TYPE}${BuildConfig.BUILD_VARIANT_TYPE} + Emoji Version : ${getEmojiVersionString(context)} + RenderBigEmoji : ${canRenderEmojiAtFontSize(1024f)} + DontKeepActivities: ${getDontKeepActivities(context)} + Server Time Offset: ${misc.lastKnownServerTimeOffset} ms (last updated: ${misc.lastKnownServerTimeOffsetUpdateTime}) + Telecom : $telecomSupported + User-Agent : ${StandardUserAgentInterceptor.USER_AGENT} + SlowNotifications : ${isHavingDelayedNotifications()} + IgnoringBatteryOpt: ${PowerManagerCompat.isIgnoringBatteryOptimizations(context)} + BkgRestricted : ${if (Build.VERSION.SDK_INT >= 28) DeviceProperties.isBackgroundRestricted(context) else "N/A"} + Data Saver : ${DeviceProperties.getDataSaverState(context)} + APNG Animation : ${DeviceProperties.shouldAllowApngStickerAnimation(context)} + ApkManifestUrl : ${BuildConfig.APK_UPDATE_MANIFEST_URL?.takeIf { BuildConfig.MANAGES_APP_UPDATES } ?: "N/A"} + App : ${getAppInfo(context)} + Package : ${BuildConfig.APPLICATION_ID} (${getSigningString(context)}) + """.trimIndent() + } + + private fun getAppInfo(context: Context): String { + return try { + val packageManager = context.packageManager + val appLabel = packageManager.getApplicationLabel(packageManager.getApplicationInfo(context.packageName, 0)) + val versionName = packageManager.getPackageInfo(context.packageName, 0).versionName + val manifestApkVersion = Util.getManifestApkVersion(context) + + "$appLabel $versionName (${BuildConfig.CANONICAL_VERSION_CODE}, $manifestApkVersion) (${BuildConfig.GIT_HASH})" + } catch (_: PackageManager.NameNotFoundException) { + "Unknown" + } + } + + private fun getMemoryUsage(): String { + val info = Runtime.getRuntime() + val totalMemory = info.totalMemory() + + return String.format( + Locale.ENGLISH, + "%.0fM (%.2f%% free, %.0fM max)", + totalMemory.bytes.inMebiBytes, + info.freeMemory().toFloat() / totalMemory * 100f, + info.maxMemory().bytes.inMebiBytes + ) + } + + private fun getMemoryClass(context: Context): String { + val activityManager = ServiceUtil.getActivityManager(context) + var lowMem = "" + + if (activityManager.isLowRamDevice) { + lowMem = ", low-mem device" + } + + return activityManager.memoryClass.toString() + lowMem + } + + private fun getMemoryInfo(context: Context): String { + val info = DeviceProperties.getMemoryInfo(context) + return "availMem: ${info.availMem.bytes.inMebiBytes.roundedString(2)} MiB, totalMem: ${info.totalMem.bytes.inMebiBytes.roundedString(2)} MiB, threshold: ${info.threshold.bytes.inMebiBytes.roundedString(2)} MiB, lowMemory: ${info.lowMemory}" + } + + private fun getScreenResolution(context: Context): String { + val displayMetrics = DisplayMetrics() + val windowManager = ServiceUtil.getWindowManager(context) + + windowManager.defaultDisplay.getMetrics(displayMetrics) + return displayMetrics.widthPixels.toString() + "x" + displayMetrics.heightPixels + } + + private fun getScreenRefreshRate(context: Context): String { + return String.format(Locale.ENGLISH, "%.2f hz", ServiceUtil.getWindowManager(context).defaultDisplay.refreshRate) + } + + private fun getSigningString(context: Context): String { + return AppSignatureUtil.getAppSignature(context) + } + + private fun getPlayServicesString(context: Context): String { + val result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) + return if (result == ConnectionResult.SUCCESS) { + "true" + } else { + "false ($result)" + } + } + + private fun getEmojiVersionString(context: Context): String { + val version = readVersion(context) + + return if (version == null) { + "None" + } else { + "${version.version} (${version.density})" + } + } + + private fun getCensoredAci(): String { + val aci = account.aci + + if (aci != null) { + val aciString = aci.toString() + val lastThree = aciString.substring(aciString.length - 3) + + return "********-****-****-****-*********$lastThree" + } else { + return "N/A" + } + } + + private fun getDontKeepActivities(context: Context): String { + val setting = Settings.Global.getInt(context.contentResolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) + return if (setting == 0) { + "false" + } else { + "true" + } + } +}