diff --git a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java index fcb2d9c469..9f2584bbe5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java +++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java @@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.util.AppSignatureUtil; import org.thoughtcrime.securesms.util.ByteUnit; import org.thoughtcrime.securesms.util.CensorshipUtil; +import org.thoughtcrime.securesms.util.DeviceProperties; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; @@ -54,6 +55,7 @@ public class LogSectionSystemInfo implements LogSection { 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("Censored : ").append(CensorshipUtil.isCensored(context)).append("\n"); builder.append("Play Services : ").append(getPlayServicesString(context)).append("\n"); @@ -102,6 +104,12 @@ public class LogSectionSystemInfo implements LogSection { 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); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/DeviceProperties.java b/app/src/main/java/org/thoughtcrime/securesms/util/DeviceProperties.java index 7c34028bd1..3c60c4d8c1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/DeviceProperties.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/DeviceProperties.java @@ -1,7 +1,9 @@ package org.thoughtcrime.securesms.util; import android.app.ActivityManager; +import android.app.ActivityManager.MemoryInfo; import android.content.Context; +import android.os.Build; import androidx.annotation.NonNull; @@ -15,7 +17,17 @@ public final class DeviceProperties { * large numbers of APNGs simultaneously. */ public static boolean shouldAllowApngStickerAnimation(@NonNull Context context) { - return !isLowMemoryDevice(context) && getMemoryClass(context) >= FeatureFlags.animatedStickerMinimumMemory(); + if (Build.VERSION.SDK_INT < 26) { + return false; + } + + MemoryInfo memoryInfo = getMemoryInfo(context); + int memoryMb = (int) ByteUnit.BYTES.toMegabytes(memoryInfo.totalMem); + + return !isLowMemoryDevice(context) && + !memoryInfo.lowMemory && + (memoryMb >= FeatureFlags.animatedStickerMinimumTotalMemoryMb() || + getMemoryClass(context) >= FeatureFlags.animatedStickerMinimumMemoryClass()); } public static boolean isLowMemoryDevice(@NonNull Context context) { @@ -27,4 +39,13 @@ public final class DeviceProperties { ActivityManager activityManager = ServiceUtil.getActivityManager(context); return activityManager.getMemoryClass(); } + + public static @NonNull MemoryInfo getMemoryInfo(@NonNull Context context) { + MemoryInfo info = new MemoryInfo(); + ActivityManager activityManager = ServiceUtil.getActivityManager(context); + + activityManager.getMemoryInfo(info); + + return info; + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java index f2e866c2e7..6f18fe1462 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java @@ -49,30 +49,31 @@ public final class FeatureFlags { private static final long FETCH_INTERVAL = TimeUnit.HOURS.toMillis(2); - private static final String USERNAMES = "android.usernames"; - private static final String GROUPS_V2_RECOMMENDED_LIMIT = "global.groupsv2.maxGroupSize"; - private static final String GROUPS_V2_HARD_LIMIT = "global.groupsv2.groupSizeHardLimit"; - private static final String GROUP_NAME_MAX_LENGTH = "global.groupsv2.maxNameLength"; - private static final String INTERNAL_USER = "android.internalUser"; - private static final String VERIFY_V2 = "android.verifyV2"; - private static final String PHONE_NUMBER_PRIVACY_VERSION = "android.phoneNumberPrivacyVersion"; - private static final String CLIENT_EXPIRATION = "android.clientExpiration"; - public static final String RESEARCH_MEGAPHONE_1 = "research.megaphone.1"; - public static final String DONATE_MEGAPHONE = "android.donate"; - private static final String VIEWED_RECEIPTS = "android.viewed.receipts"; - private static final String GROUP_CALLING = "android.groupsv2.calling.2"; - private static final String GV1_MANUAL_MIGRATE = "android.groupsV1Migration.manual"; - private static final String GV1_FORCED_MIGRATE = "android.groupsV1Migration.forced"; - private static final String GV1_MIGRATION_JOB = "android.groupsV1Migration.job"; - private static final String SEND_VIEWED_RECEIPTS = "android.sendViewedReceipts"; - private static final String CUSTOM_VIDEO_MUXER = "android.customVideoMuxer"; - private static final String CDS_REFRESH_INTERVAL = "cds.syncInterval.seconds"; - private static final String AUTOMATIC_SESSION_RESET = "android.automaticSessionReset.2"; - private static final String AUTOMATIC_SESSION_INTERVAL = "android.automaticSessionResetInterval"; - private static final String DEFAULT_MAX_BACKOFF = "android.defaultMaxBackoff"; - private static final String OKHTTP_AUTOMATIC_RETRY = "android.okhttpAutomaticRetry"; - private static final String SHARE_SELECTION_LIMIT = "android.share.limit"; - private static final String ANIMATED_STICKER_MIN_MEMORY = "android.animatedStickerMinMemory"; + private static final String USERNAMES = "android.usernames"; + private static final String GROUPS_V2_RECOMMENDED_LIMIT = "global.groupsv2.maxGroupSize"; + private static final String GROUPS_V2_HARD_LIMIT = "global.groupsv2.groupSizeHardLimit"; + private static final String GROUP_NAME_MAX_LENGTH = "global.groupsv2.maxNameLength"; + private static final String INTERNAL_USER = "android.internalUser"; + private static final String VERIFY_V2 = "android.verifyV2"; + private static final String PHONE_NUMBER_PRIVACY_VERSION = "android.phoneNumberPrivacyVersion"; + private static final String CLIENT_EXPIRATION = "android.clientExpiration"; + public static final String RESEARCH_MEGAPHONE_1 = "research.megaphone.1"; + public static final String DONATE_MEGAPHONE = "android.donate"; + private static final String VIEWED_RECEIPTS = "android.viewed.receipts"; + private static final String GROUP_CALLING = "android.groupsv2.calling.2"; + private static final String GV1_MANUAL_MIGRATE = "android.groupsV1Migration.manual"; + private static final String GV1_FORCED_MIGRATE = "android.groupsV1Migration.forced"; + private static final String GV1_MIGRATION_JOB = "android.groupsV1Migration.job"; + private static final String SEND_VIEWED_RECEIPTS = "android.sendViewedReceipts"; + private static final String CUSTOM_VIDEO_MUXER = "android.customVideoMuxer"; + private static final String CDS_REFRESH_INTERVAL = "cds.syncInterval.seconds"; + private static final String AUTOMATIC_SESSION_RESET = "android.automaticSessionReset.2"; + private static final String AUTOMATIC_SESSION_INTERVAL = "android.automaticSessionResetInterval"; + private static final String DEFAULT_MAX_BACKOFF = "android.defaultMaxBackoff"; + private static final String OKHTTP_AUTOMATIC_RETRY = "android.okhttpAutomaticRetry"; + private static final String SHARE_SELECTION_LIMIT = "android.share.limit"; + private static final String ANIMATED_STICKER_MIN_MEMORY = "android.animatedStickerMinMemory"; + private static final String ANIMATED_STICKER_MIN_TOTAL_MEMORY = "android.animatedStickerMinTotalMemory"; /** * We will only store remote values for flags in this set. If you want a flag to be controllable @@ -102,7 +103,8 @@ public final class FeatureFlags { DEFAULT_MAX_BACKOFF, OKHTTP_AUTOMATIC_RETRY, SHARE_SELECTION_LIMIT, - ANIMATED_STICKER_MIN_MEMORY + ANIMATED_STICKER_MIN_MEMORY, + ANIMATED_STICKER_MIN_TOTAL_MEMORY ); @VisibleForTesting @@ -142,7 +144,8 @@ public final class FeatureFlags { DEFAULT_MAX_BACKOFF, OKHTTP_AUTOMATIC_RETRY, SHARE_SELECTION_LIMIT, - ANIMATED_STICKER_MIN_MEMORY + ANIMATED_STICKER_MIN_MEMORY, + ANIMATED_STICKER_MIN_TOTAL_MEMORY ); /** @@ -327,11 +330,16 @@ public final class FeatureFlags { return getBoolean(OKHTTP_AUTOMATIC_RETRY, false); } - /** The minimum amount of memory required for rendering animated stickers in the keyboard and such */ - public static int animatedStickerMinimumMemory() { + /** The minimum memory class required for rendering animated stickers in the keyboard and such */ + public static int animatedStickerMinimumMemoryClass() { return getInteger(ANIMATED_STICKER_MIN_MEMORY, 193); } + /** The minimum total memory for rendering animated stickers in the keyboard and such */ + public static int animatedStickerMinimumTotalMemoryMb() { + return getInteger(ANIMATED_STICKER_MIN_TOTAL_MEMORY, (int) ByteUnit.GIGABYTES.toMegabytes(3)); + } + /** Only for rendering debug info. */ public static synchronized @NonNull Map getMemoryValues() { return new TreeMap<>(REMOTE_VALUES);