Fix emoji on odd densities and add internal pref to force built-in.

This commit is contained in:
Alex Hart 2021-05-04 09:25:45 -03:00 committed by Cody Henthorne
parent 6c2adfeec2
commit efc3e7b25d
7 changed files with 68 additions and 11 deletions

View file

@ -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

View file

@ -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.

View file

@ -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() + ")";
}
}
}

View file

@ -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);
}
}

View file

@ -2418,6 +2418,10 @@
<string name="preferences__internal_force_censorship" translatable="false">Force censorship</string>
<string name="preferences__internal_force_censorship_description" translatable="false">Force the app to behave as if it is in a country where Signal is censored.</string>
<string name="preferences__internal_conversations_and_shortcuts" translatable="false">Conversations and Shortcuts</string>
<string name="preferences__internal_emoji" translatable="false">Emoji</string>
<string name="preferences__internal_use_built_in_emoji_set" translatable="false">Use built-in emoji set.</string>
<string name="preferences__internal_current_version_builtin" translatable="false">Current version: Built-In</string>
<string name="preferences__internal_current_version_d_at_density_s" translatable="false">Current version: %1$d at density %2$s</string>
<string name="preferences__internal_delete_all_dynamic_shortcuts" translatable="false">Delete all dynamic shortcuts</string>
<string name="preferences__internal_click_to_delete_all_dynamic_shortcuts" translatable="false">Click to delete all dynamic shortcuts</string>
<string name="preferences__internal_disable_profile_sharing" translatable="false">Disable Profile Sharing</string>

View file

@ -39,8 +39,8 @@
android:title="@string/preferences__internal_display">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="internal.recipient_details"
android:defaultValue="false"
android:key="internal.recipient_details"
android:summary="@string/preferences__internal_user_details_description"
android:title="@string/preferences__internal_user_details" />
@ -124,4 +124,13 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/preferences__internal_emoji">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="internal.force_built_in_emoji"
android:title="@string/preferences__internal_use_built_in_emoji_set" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -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));