diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiSource.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiSource.kt
index ebf77c593..e4dd45487 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiSource.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiSource.kt
@@ -2,19 +2,18 @@ package org.thoughtcrime.securesms.emoji
import android.net.Uri
import androidx.annotation.WorkerThread
-import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.emoji.Emoji
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
import org.thoughtcrime.securesms.components.emoji.StaticEmojiPageModel
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
+import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader
import org.thoughtcrime.securesms.util.ScreenDensity
import java.io.InputStream
import java.util.concurrent.CountDownLatch
import java.util.concurrent.atomic.AtomicReference
-import kotlin.math.min
/**
* The entry point for the application to request Emoji data for custom emojis.
@@ -88,27 +87,27 @@ class EmojiSource(
}
private fun loadRemoteBasedEmojis(): EmojiSource? {
+ if (SignalStore.internalValues().forceBuiltInEmoji()) {
+ return null
+ }
+
val context = ApplicationDependencies.getApplication()
val version = EmojiFiles.Version.readVersion(context) ?: return null
val emojiData = EmojiFiles.getLatestEmojiData(context, version)
val density = ScreenDensity.xhdpiRelativeDensityScaleFactor(version.density)
return emojiData?.let {
- val decodeScale = min(1f, context.resources.getDimension(R.dimen.emoji_drawer_size) / it.metrics.rawHeight)
-
- EmojiSource(decodeScale * density, it) { uri: Uri -> EmojiPageReference(DecryptableStreamUriLoader.DecryptableUri(uri)) }
+ EmojiSource(density, it) { uri: Uri -> EmojiPageReference(DecryptableStreamUriLoader.DecryptableUri(uri)) }
}
}
private fun loadAssetBasedEmojis(): EmojiSource {
- val context = ApplicationDependencies.getApplication()
val emojiData: InputStream = ApplicationDependencies.getApplication().assets.open("emoji/emoji_data.json")
emojiData.use {
val parsedData: ParsedEmojiData = EmojiJsonParser.parse(it, ::getAssetsUri).getOrThrow()
- val decodeScale = min(1f, context.resources.getDimension(R.dimen.emoji_drawer_size) / parsedData.metrics.rawHeight)
return EmojiSource(
- decodeScale * ScreenDensity.xhdpiRelativeDensityScaleFactor("xhdpi"),
+ ScreenDensity.xhdpiRelativeDensityScaleFactor("xhdpi"),
parsedData.copy(
displayPages = parsedData.displayPages + PAGE_EMOTICONS,
dataPages = parsedData.dataPages + PAGE_EMOTICONS
diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java
index 7e312c1af..79a18ee0b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/InternalValues.java
@@ -17,6 +17,7 @@ public final class InternalValues extends SignalStoreValues {
public static final String GV2_DISABLE_AUTOMIGRATE_NOTIFICATION = "internal.gv2.disable_automigrate_notification";
public static final String RECIPIENT_DETAILS = "internal.recipient_details";
public static final String FORCE_CENSORSHIP = "internal.force_censorship";
+ public static final String FORCE_BUILT_IN_EMOJI = "internal.force_built_in_emoji";
InternalValues(KeyValueStore store) {
super(store);
@@ -80,6 +81,13 @@ public final class InternalValues extends SignalStoreValues {
return FeatureFlags.internalUser() && getBoolean(FORCE_CENSORSHIP, false);
}
+ /**
+ * Force the app to behave as if it is in a country where Signal is censored.
+ */
+ public synchronized boolean forceBuiltInEmoji() {
+ return FeatureFlags.internalUser() && getBoolean(FORCE_BUILT_IN_EMOJI, false);
+ }
+
/**
* Disable initiating a GV1->GV2 auto-migration. You can still recognize a group has been
* auto-migrated.
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 9d329b8bc..a1a0b3310 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/logsubmit/LogSectionSystemInfo.java
@@ -14,6 +14,8 @@ import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import org.thoughtcrime.securesms.BuildConfig;
+import org.thoughtcrime.securesms.emoji.EmojiFiles;
+import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.util.AppSignatureUtil;
import org.thoughtcrime.securesms.util.ByteUnit;
import org.thoughtcrime.securesms.util.CensorshipUtil;
@@ -66,6 +68,7 @@ public class LogSectionSystemInfo implements LogSection {
builder.append("Linked Devices: ").append(TextSecurePreferences.isMultiDevice(context)).append("\n");
builder.append("First Version : ").append(TextSecurePreferences.getFirstInstallVersion(context)).append("\n");
builder.append("Days Installed: ").append(VersionTracker.getDaysSinceFirstInstalled(context)).append("\n");
+ builder.append("Emoji Version : ").append(getEmojiVersionString(context)).append("\n");
builder.append("App : ");
try {
builder.append(pm.getApplicationLabel(pm.getApplicationInfo(context.getPackageName(), 0)))
@@ -146,4 +149,14 @@ public class LogSectionSystemInfo implements LogSection {
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() + ")";
+ }
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/InternalOptionsPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/InternalOptionsPreferenceFragment.java
index 7da62d2c7..6bd8fa931 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/preferences/InternalOptionsPreferenceFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/InternalOptionsPreferenceFragment.java
@@ -16,6 +16,8 @@ import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
+import org.thoughtcrime.securesms.emoji.EmojiFiles;
+import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob;
@@ -49,6 +51,7 @@ public class InternalOptionsPreferenceFragment extends CorrectedPreferenceFragme
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DISABLE_AUTOMIGRATE_INITIATION, SignalStore.internalValues().disableGv1AutoMigrateInitiation());
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DISABLE_AUTOMIGRATE_NOTIFICATION, SignalStore.internalValues().disableGv1AutoMigrateNotification());
initializeSwitchPreference(preferenceDataStore, InternalValues.FORCE_CENSORSHIP, SignalStore.internalValues().forcedCensorship());
+ initializeSwitchPreference(preferenceDataStore, InternalValues.FORCE_BUILT_IN_EMOJI, SignalStore.internalValues().forceBuiltInEmoji());
findPreference("pref_copy_payments_data").setOnPreferenceClickListener(preference -> {
new AlertDialog.Builder(getContext())
@@ -122,5 +125,21 @@ public class InternalOptionsPreferenceFragment extends CorrectedPreferenceFragme
super.onResume();
//noinspection ConstantConditions
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__internal_preferences);
+
+ SimpleTask.run(getViewLifecycleOwner().getLifecycle(),
+ () -> EmojiFiles.Version.readVersion(requireContext()),
+ version -> {
+ if (version != null) {
+ findPreference(InternalValues.FORCE_BUILT_IN_EMOJI).setSummary(getString(R.string.preferences__internal_current_version_d_at_density_s, version.getVersion(), version.getDensity()));
+ } else {
+ findPreference(InternalValues.FORCE_BUILT_IN_EMOJI).setSummary(getString(R.string.preferences__internal_current_version_builtin));
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ SignalExecutors.BOUNDED.execute(EmojiSource::refresh);
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 298079423..7a7f4381e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2418,6 +2418,10 @@
Force censorship
Force the app to behave as if it is in a country where Signal is censored.
Conversations and Shortcuts
+ Emoji
+ Use built-in emoji set.
+ Current version: Built-In
+ Current version: %1$d at density %2$s
Delete all dynamic shortcuts
Click to delete all dynamic shortcuts
Disable Profile Sharing
diff --git a/app/src/main/res/xml/preferences_internal.xml b/app/src/main/res/xml/preferences_internal.xml
index 16dfaed2c..6ce1205c8 100644
--- a/app/src/main/res/xml/preferences_internal.xml
+++ b/app/src/main/res/xml/preferences_internal.xml
@@ -39,8 +39,8 @@
android:title="@string/preferences__internal_display">
@@ -124,4 +124,13 @@
+
+
+
+
+
+
diff --git a/app/src/test/java/org/thoughtcrime/securesms/components/emoji/EmojiUtilTest_isEmoji.java b/app/src/test/java/org/thoughtcrime/securesms/components/emoji/EmojiUtilTest_isEmoji.java
index 38d718e00..586ed8e89 100644
--- a/app/src/test/java/org/thoughtcrime/securesms/components/emoji/EmojiUtilTest_isEmoji.java
+++ b/app/src/test/java/org/thoughtcrime/securesms/components/emoji/EmojiUtilTest_isEmoji.java
@@ -19,6 +19,8 @@ import org.robolectric.annotation.Config;
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.emoji.EmojiSource;
+import org.thoughtcrime.securesms.keyvalue.InternalValues;
+import org.thoughtcrime.securesms.keyvalue.SignalStore;
import java.io.IOException;
import java.util.Arrays;
@@ -31,7 +33,7 @@ import static org.mockito.Mockito.mock;
@RunWith(ParameterizedRobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*", "androidx.*" })
-@PrepareForTest({ApplicationDependencies.class, AttachmentSecretProvider.class})
+@PrepareForTest({ApplicationDependencies.class, AttachmentSecretProvider.class, SignalStore.class, InternalValues.class})
public class EmojiUtilTest_isEmoji {
public @Rule PowerMockRule rule = new PowerMockRule();
@@ -68,13 +70,16 @@ public class EmojiUtilTest_isEmoji {
}
@Test
- public void isEmoji() {
+ public void isEmoji() throws Exception {
Context context = ApplicationProvider.getApplicationContext();
PowerMockito.mockStatic(ApplicationDependencies.class);
PowerMockito.when(ApplicationDependencies.getApplication()).thenReturn((Application) context);
PowerMockito.mockStatic(AttachmentSecretProvider.class);
PowerMockito.when(AttachmentSecretProvider.getInstance(any())).thenThrow(IOException.class);
+ PowerMockito.whenNew(SignalStore.class).withAnyArguments().thenReturn(null);
+ PowerMockito.mockStatic(SignalStore.class);
+ PowerMockito.when(SignalStore.internalValues()).thenReturn(PowerMockito.mock(InternalValues.class));
EmojiSource.refresh();
assertEquals(output, EmojiUtil.isEmoji(context, input));