Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set and require android:supportsRtl="true" for RTL layout #44538

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,30 @@

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import androidx.annotation.Nullable;
import androidx.core.text.TextUtilsCompat;
import androidx.core.util.Preconditions;
import androidx.core.view.ViewCompat;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Nullsafe;
import java.lang.reflect.Method;
import java.util.Locale;

@Nullsafe(Nullsafe.Mode.LOCAL)
public class I18nUtil {
private static I18nUtil sharedI18nUtilInstance = null;
private static @Nullable I18nUtil sharedI18nUtilInstance = null;

private static final String TAG = "I18nUtil";
private static final String SHARED_PREFS_NAME = "com.facebook.react.modules.i18nmanager.I18nUtil";
private static final String KEY_FOR_PREFS_ALLOWRTL = "RCTI18nUtil_allowRTL";
private static final String KEY_FOR_PREFS_FORCERTL = "RCTI18nUtil_forceRTL";
private static final String KEY_FOR_PERFS_MAKE_RTL_FLIP_LEFT_AND_RIGHT_STYLES =
"RCTI18nUtil_makeRTLFlipLeftAndRightStyles";

private boolean mHasCheckedRtlSupport = false;
private boolean mHasRtlSupport = true;

private I18nUtil() {
// Exists only to defeat instantiation.
}
Expand All @@ -42,19 +53,46 @@ public static I18nUtil getInstance() {
* </ul>
*/
public boolean isRTL(Context context) {
if (!applicationHasRtlSupport(context)) {
return false;
}

if (isRTLForced(context)) {
return true;
}

return isRTLAllowed(context) && isDevicePreferredLanguageRTL();
}

/**
* Android relies on the presence of `android:supportsRtl="true"` being set in order to resolve
* RTL as a layout direction for native Android views. RTL in React Native relies on this being
* set.
*/
private boolean applicationHasRtlSupport(Context context) {
if (!mHasCheckedRtlSupport) {
mHasCheckedRtlSupport = true;
ApplicationInfo applicationInfo = context.getApplicationInfo();
try {
Method hasRtlSupport = ApplicationInfo.class.getMethod("hasRtlSupport");
mHasRtlSupport =
Preconditions.checkNotNull((Boolean) hasRtlSupport.invoke(applicationInfo));
} catch (ReflectiveOperationException e) {
FLog.w(TAG, "Failed to check if application has RTL support");
}
}
return mHasRtlSupport;
}

/**
* Should be used very early during app start up Before the bridge is initialized
*
* @return whether the app allows RTL layout, default is true
*/
private boolean isRTLAllowed(Context context) {
return isPrefSet(context, KEY_FOR_PREFS_ALLOWRTL, true);
// We should only claim to allow RTL if `android:supportsRtl="true"` is set, otherwise the
// platform apart from Yoga ignores layout direction.
return applicationHasRtlSupport(context) && isPrefSet(context, KEY_FOR_PREFS_ALLOWRTL, true);
}

public void allowRTL(Context context, boolean allowRTL) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
Expand Down
3 changes: 2 additions & 1 deletion packages/rn-tester/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:supportsRtl="true">
<activity
android:name=".RNTesterActivity"
android:label="@string/app_name"
Expand Down
Loading