kopia lustrzana https://github.com/ryukoposting/Signal-Android
Fix emoji on odd densities and add internal pref to force built-in.
rodzic
6c2adfeec2
commit
efc3e7b25d
|
@ -2,19 +2,18 @@ package org.thoughtcrime.securesms.emoji
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import org.thoughtcrime.securesms.R
|
|
||||||
import org.thoughtcrime.securesms.components.emoji.Emoji
|
import org.thoughtcrime.securesms.components.emoji.Emoji
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
|
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
|
||||||
import org.thoughtcrime.securesms.components.emoji.StaticEmojiPageModel
|
import org.thoughtcrime.securesms.components.emoji.StaticEmojiPageModel
|
||||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo
|
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo
|
||||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree
|
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader
|
||||||
import org.thoughtcrime.securesms.util.ScreenDensity
|
import org.thoughtcrime.securesms.util.ScreenDensity
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The entry point for the application to request Emoji data for custom emojis.
|
* The entry point for the application to request Emoji data for custom emojis.
|
||||||
|
@ -88,27 +87,27 @@ class EmojiSource(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadRemoteBasedEmojis(): EmojiSource? {
|
private fun loadRemoteBasedEmojis(): EmojiSource? {
|
||||||
|
if (SignalStore.internalValues().forceBuiltInEmoji()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
val context = ApplicationDependencies.getApplication()
|
val context = ApplicationDependencies.getApplication()
|
||||||
val version = EmojiFiles.Version.readVersion(context) ?: return null
|
val version = EmojiFiles.Version.readVersion(context) ?: return null
|
||||||
val emojiData = EmojiFiles.getLatestEmojiData(context, version)
|
val emojiData = EmojiFiles.getLatestEmojiData(context, version)
|
||||||
val density = ScreenDensity.xhdpiRelativeDensityScaleFactor(version.density)
|
val density = ScreenDensity.xhdpiRelativeDensityScaleFactor(version.density)
|
||||||
|
|
||||||
return emojiData?.let {
|
return emojiData?.let {
|
||||||
val decodeScale = min(1f, context.resources.getDimension(R.dimen.emoji_drawer_size) / it.metrics.rawHeight)
|
EmojiSource(density, it) { uri: Uri -> EmojiPageReference(DecryptableStreamUriLoader.DecryptableUri(uri)) }
|
||||||
|
|
||||||
EmojiSource(decodeScale * density, it) { uri: Uri -> EmojiPageReference(DecryptableStreamUriLoader.DecryptableUri(uri)) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAssetBasedEmojis(): EmojiSource {
|
private fun loadAssetBasedEmojis(): EmojiSource {
|
||||||
val context = ApplicationDependencies.getApplication()
|
|
||||||
val emojiData: InputStream = ApplicationDependencies.getApplication().assets.open("emoji/emoji_data.json")
|
val emojiData: InputStream = ApplicationDependencies.getApplication().assets.open("emoji/emoji_data.json")
|
||||||
|
|
||||||
emojiData.use {
|
emojiData.use {
|
||||||
val parsedData: ParsedEmojiData = EmojiJsonParser.parse(it, ::getAssetsUri).getOrThrow()
|
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(
|
return EmojiSource(
|
||||||
decodeScale * ScreenDensity.xhdpiRelativeDensityScaleFactor("xhdpi"),
|
ScreenDensity.xhdpiRelativeDensityScaleFactor("xhdpi"),
|
||||||
parsedData.copy(
|
parsedData.copy(
|
||||||
displayPages = parsedData.displayPages + PAGE_EMOTICONS,
|
displayPages = parsedData.displayPages + PAGE_EMOTICONS,
|
||||||
dataPages = parsedData.dataPages + PAGE_EMOTICONS
|
dataPages = parsedData.dataPages + PAGE_EMOTICONS
|
||||||
|
|
|
@ -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 GV2_DISABLE_AUTOMIGRATE_NOTIFICATION = "internal.gv2.disable_automigrate_notification";
|
||||||
public static final String RECIPIENT_DETAILS = "internal.recipient_details";
|
public static final String RECIPIENT_DETAILS = "internal.recipient_details";
|
||||||
public static final String FORCE_CENSORSHIP = "internal.force_censorship";
|
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) {
|
InternalValues(KeyValueStore store) {
|
||||||
super(store);
|
super(store);
|
||||||
|
@ -80,6 +81,13 @@ public final class InternalValues extends SignalStoreValues {
|
||||||
return FeatureFlags.internalUser() && getBoolean(FORCE_CENSORSHIP, false);
|
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
|
* Disable initiating a GV1->GV2 auto-migration. You can still recognize a group has been
|
||||||
* auto-migrated.
|
* auto-migrated.
|
||||||
|
|
|
@ -14,6 +14,8 @@ import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.GoogleApiAvailability;
|
import com.google.android.gms.common.GoogleApiAvailability;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.BuildConfig;
|
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.AppSignatureUtil;
|
||||||
import org.thoughtcrime.securesms.util.ByteUnit;
|
import org.thoughtcrime.securesms.util.ByteUnit;
|
||||||
import org.thoughtcrime.securesms.util.CensorshipUtil;
|
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("Linked Devices: ").append(TextSecurePreferences.isMultiDevice(context)).append("\n");
|
||||||
builder.append("First Version : ").append(TextSecurePreferences.getFirstInstallVersion(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("Days Installed: ").append(VersionTracker.getDaysSinceFirstInstalled(context)).append("\n");
|
||||||
|
builder.append("Emoji Version : ").append(getEmojiVersionString(context)).append("\n");
|
||||||
builder.append("App : ");
|
builder.append("App : ");
|
||||||
try {
|
try {
|
||||||
builder.append(pm.getApplicationLabel(pm.getApplicationInfo(context.getPackageName(), 0)))
|
builder.append(pm.getApplicationLabel(pm.getApplicationInfo(context.getPackageName(), 0)))
|
||||||
|
@ -146,4 +149,14 @@ public class LogSectionSystemInfo implements LogSection {
|
||||||
int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
|
int result = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context);
|
||||||
return result == ConnectionResult.SUCCESS ? "true" : "false (" + result + ")";
|
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() + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
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.RefreshAttributesJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
|
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RemoteConfigRefreshJob;
|
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_INITIATION, SignalStore.internalValues().disableGv1AutoMigrateInitiation());
|
||||||
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DISABLE_AUTOMIGRATE_NOTIFICATION, SignalStore.internalValues().disableGv1AutoMigrateNotification());
|
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DISABLE_AUTOMIGRATE_NOTIFICATION, SignalStore.internalValues().disableGv1AutoMigrateNotification());
|
||||||
initializeSwitchPreference(preferenceDataStore, InternalValues.FORCE_CENSORSHIP, SignalStore.internalValues().forcedCensorship());
|
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 -> {
|
findPreference("pref_copy_payments_data").setOnPreferenceClickListener(preference -> {
|
||||||
new AlertDialog.Builder(getContext())
|
new AlertDialog.Builder(getContext())
|
||||||
|
@ -122,5 +125,21 @@ public class InternalOptionsPreferenceFragment extends CorrectedPreferenceFragme
|
||||||
super.onResume();
|
super.onResume();
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__internal_preferences);
|
((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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2418,6 +2418,10 @@
|
||||||
<string name="preferences__internal_force_censorship" translatable="false">Force censorship</string>
|
<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_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_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_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_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>
|
<string name="preferences__internal_disable_profile_sharing" translatable="false">Disable Profile Sharing</string>
|
||||||
|
|
|
@ -39,8 +39,8 @@
|
||||||
android:title="@string/preferences__internal_display">
|
android:title="@string/preferences__internal_display">
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||||
android:key="internal.recipient_details"
|
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
|
android:key="internal.recipient_details"
|
||||||
android:summary="@string/preferences__internal_user_details_description"
|
android:summary="@string/preferences__internal_user_details_description"
|
||||||
android:title="@string/preferences__internal_user_details" />
|
android:title="@string/preferences__internal_user_details" />
|
||||||
|
|
||||||
|
@ -124,4 +124,13 @@
|
||||||
|
|
||||||
</PreferenceCategory>
|
</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>
|
</PreferenceScreen>
|
||||||
|
|
|
@ -19,6 +19,8 @@ import org.robolectric.annotation.Config;
|
||||||
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
|
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.emoji.EmojiSource;
|
import org.thoughtcrime.securesms.emoji.EmojiSource;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.InternalValues;
|
||||||
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -31,7 +33,7 @@ import static org.mockito.Mockito.mock;
|
||||||
@RunWith(ParameterizedRobolectricTestRunner.class)
|
@RunWith(ParameterizedRobolectricTestRunner.class)
|
||||||
@Config(manifest = Config.NONE, application = Application.class)
|
@Config(manifest = Config.NONE, application = Application.class)
|
||||||
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*", "androidx.*" })
|
@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 class EmojiUtilTest_isEmoji {
|
||||||
|
|
||||||
public @Rule PowerMockRule rule = new PowerMockRule();
|
public @Rule PowerMockRule rule = new PowerMockRule();
|
||||||
|
@ -68,13 +70,16 @@ public class EmojiUtilTest_isEmoji {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isEmoji() {
|
public void isEmoji() throws Exception {
|
||||||
Context context = ApplicationProvider.getApplicationContext();
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
PowerMockito.mockStatic(ApplicationDependencies.class);
|
PowerMockito.mockStatic(ApplicationDependencies.class);
|
||||||
PowerMockito.when(ApplicationDependencies.getApplication()).thenReturn((Application) context);
|
PowerMockito.when(ApplicationDependencies.getApplication()).thenReturn((Application) context);
|
||||||
PowerMockito.mockStatic(AttachmentSecretProvider.class);
|
PowerMockito.mockStatic(AttachmentSecretProvider.class);
|
||||||
PowerMockito.when(AttachmentSecretProvider.getInstance(any())).thenThrow(IOException.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();
|
EmojiSource.refresh();
|
||||||
|
|
||||||
assertEquals(output, EmojiUtil.isEmoji(context, input));
|
assertEquals(output, EmojiUtil.isEmoji(context, input));
|
||||||
|
|
Ładowanie…
Reference in New Issue