Search code examples
androidarabicright-to-left

Bug when formatting "%d - %d" in RTL on Samsung devices with Android 8.0


I have an app that supports RTL. When formatting a score between two teams I write something along the lines of:

t1.setText(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));

Which outputs "0 - 1" on the Android emulator if my textfield is set to textDirection="locale", on all my test-devices running Android 8 and Android 9, on my Huawei and basically everywhere. But if I test this on a Samsung S7 with Android 8.0 it returns "1 - 0". I tested both on a physical device and on the device lab from Samsung: https://developer.samsung.com/remotetestlab/rtlDeviceList.action

Is this the wrong way of doing this? How can I format the score so it works on both LTR and RTL on all devices when I have a single text field containing the score? This works perfectly on most devices out there but I seem to be missing something in regards to why it breaks on Samsung devices.

Here is my code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Home team won 1-0"/>

    <TextView
        android:id="@+id/t1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layoutDirection="locale"
        android:text="1-0"
        />
    <TextView
        android:id="@+id/t2"
        android:layoutDirection="rtl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />
    <TextView
        android:id="@+id/t3"
        android:textDirection="locale"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />
    <TextView
        android:textDirection="rtl"
        android:id="@+id/t4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />
    <TextView
        android:textDirection="rtl"
        android:id="@+id/t5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />
    <TextView
        android:textDirection="locale"
        android:id="@+id/t6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />
    <TextView
        android:textDirection="locale"
        android:id="@+id/t7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />
    <TextView
        android:textDirection="locale"
        android:id="@+id/t8"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />
    <TextView
        android:textDirection="locale"
        android:id="@+id/t9"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1-0"
        />

</LinearLayout>

App code:

t1.setText(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));
t2.setText(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));
t3.setText(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));
t4.setText(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));
t5.setText(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));
t6.setText(BidiFormatter.getInstance(Locale.forLanguageTag("ar-MA")).unicodeWrap(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0), TextDirectionHeuristicsCompat.ANYRTL_LTR));
t7.setText(BidiFormatter.getInstance(Locale.forLanguageTag("ar-MA")).unicodeWrap(String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0), TextDirectionHeuristicsCompat.RTL));
t8.setText("\u200F" + String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));
t9.setText("ع" + String.format(Locale.forLanguageTag("ar-MA"), "%d - %d", 1, 0));
setSupportActionBar(toolbar);

Emulator screenshot: enter image description here

Samsung S7 screenshot: enter image description here


Solution

  • It seems this bug/feature on Samsung devices can in my case have a workaround:

    String RTL_INDICATOR = "\u200f";
    t1.setText(String.format(Locale.forLanguageTag("ar-MA"), "%d %s- %d", 1, RTL_INDICATOR, 0));
    

    This Right-to-left-mark (https://www.fileformat.info/info/unicode/char/200f/index.htm) has to be inserted in the middle of the two integers. If inserted at the beginning of the string it doesn't resolve the issue.

    The code gets pretty ugly as I have to do this in a number of places but it works on all devices across all Android versions (that I've tested) so marking this as the answer for now.