Home | History | Annotate | Download | only in text
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.core.text;
     18 
     19 import static android.os.Build.VERSION.SDK_INT;
     20 
     21 import android.text.TextUtils;
     22 
     23 import androidx.annotation.NonNull;
     24 import androidx.annotation.Nullable;
     25 import androidx.core.view.ViewCompat;
     26 
     27 import java.util.Locale;
     28 
     29 /**
     30  * Backwards compatible version of {@link TextUtils}.
     31  */
     32 public final class TextUtilsCompat {
     33     private static final Locale ROOT = new Locale("", "");
     34     private static final String ARAB_SCRIPT_SUBTAG = "Arab";
     35     private static final String HEBR_SCRIPT_SUBTAG = "Hebr";
     36 
     37     /**
     38      * Html-encode the string.
     39      *
     40      * @param s the string to be encoded
     41      * @return the encoded string
     42      */
     43     @NonNull
     44     public static String htmlEncode(@NonNull String s) {
     45         if (SDK_INT >= 17) {
     46             return TextUtils.htmlEncode(s);
     47         } else {
     48             StringBuilder sb = new StringBuilder();
     49             char c;
     50             for (int i = 0; i < s.length(); i++) {
     51                 c = s.charAt(i);
     52                 switch (c) {
     53                     case '<':
     54                         sb.append("&lt;"); //$NON-NLS-1$
     55                         break;
     56                     case '>':
     57                         sb.append("&gt;"); //$NON-NLS-1$
     58                         break;
     59                     case '&':
     60                         sb.append("&amp;"); //$NON-NLS-1$
     61                         break;
     62                     case '\'':
     63                         //http://www.w3.org/TR/xhtml1
     64                         // The named character reference &apos; (the apostrophe, U+0027) was
     65                         // introduced in XML 1.0 but does not appear in HTML. Authors should
     66                         // therefore use &#39; instead of &apos; to work as expected in HTML 4
     67                         // user agents.
     68                         sb.append("&#39;"); //$NON-NLS-1$
     69                         break;
     70                     case '"':
     71                         sb.append("&quot;"); //$NON-NLS-1$
     72                         break;
     73                     default:
     74                         sb.append(c);
     75                 }
     76             }
     77             return sb.toString();
     78         }
     79     }
     80 
     81     /**
     82      * Returns the layout direction for a given Locale
     83      *
     84      * @param locale the {@link Locale} for which we want the layout direction, maybe be
     85      *               {@code null}.
     86      * @return the layout direction, either {@link ViewCompat#LAYOUT_DIRECTION_LTR} or
     87      *         {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
     88      */
     89     public static int getLayoutDirectionFromLocale(@Nullable Locale locale) {
     90         if (SDK_INT >= 17) {
     91             return TextUtils.getLayoutDirectionFromLocale(locale);
     92         } else {
     93             if (locale != null && !locale.equals(ROOT)) {
     94                 final String scriptSubtag = ICUCompat.maximizeAndGetScript(locale);
     95                 if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
     96 
     97                 // This is intentionally limited to Arabic and Hebrew scripts, since older
     98                 // versions of Android platform only considered those scripts to be right-to-left.
     99                 if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG)
    100                         || scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
    101                     return ViewCompat.LAYOUT_DIRECTION_RTL;
    102                 }
    103             }
    104             return ViewCompat.LAYOUT_DIRECTION_LTR;
    105         }
    106     }
    107 
    108     /**
    109      * Fallback algorithm to detect the locale direction. Rely on the first char of the
    110      * localized locale name. This will not work if the localized locale name is in English
    111      * (this is the case for ICU 4.4 and "Urdu" script)
    112      *
    113      * @param locale the {@link Locale} for which we want the layout direction, maybe be
    114      *               {@code null}.
    115      * @return the layout direction, either {@link ViewCompat#LAYOUT_DIRECTION_LTR} or
    116      *         {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
    117      */
    118     private static int getLayoutDirectionFromFirstChar(@NonNull Locale locale) {
    119         switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
    120             case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
    121             case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
    122                 return ViewCompat.LAYOUT_DIRECTION_RTL;
    123 
    124             case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
    125             default:
    126                 return ViewCompat.LAYOUT_DIRECTION_LTR;
    127         }
    128     }
    129 
    130     private TextUtilsCompat() {}
    131 }
    132