TextUtilsCompat.java revision 15375aa6fd54b036f97f99229aefab2822c8a1c9
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 17package android.support.v4.text; 18 19import android.os.Build; 20import android.support.annotation.NonNull; 21import android.support.annotation.Nullable; 22import android.support.v4.view.ViewCompat; 23 24import java.util.Locale; 25 26public final class TextUtilsCompat { 27 private static class TextUtilsCompatImpl { 28 @NonNull 29 public String htmlEncode(@NonNull String s) { 30 StringBuilder sb = new StringBuilder(); 31 char c; 32 for (int i = 0; i < s.length(); i++) { 33 c = s.charAt(i); 34 switch (c) { 35 case '<': 36 sb.append("<"); //$NON-NLS-1$ 37 break; 38 case '>': 39 sb.append(">"); //$NON-NLS-1$ 40 break; 41 case '&': 42 sb.append("&"); //$NON-NLS-1$ 43 break; 44 case '\'': 45 //http://www.w3.org/TR/xhtml1 46 // The named character reference ' (the apostrophe, U+0027) was 47 // introduced in XML 1.0 but does not appear in HTML. Authors should 48 // therefore use ' instead of ' to work as expected in HTML 4 49 // user agents. 50 sb.append("'"); //$NON-NLS-1$ 51 break; 52 case '"': 53 sb.append("""); //$NON-NLS-1$ 54 break; 55 default: 56 sb.append(c); 57 } 58 } 59 return sb.toString(); 60 } 61 62 public int getLayoutDirectionFromLocale(@Nullable Locale locale) { 63 if (locale != null && !locale.equals(ROOT)) { 64 final String scriptSubtag = ICUCompat.maximizeAndGetScript(locale); 65 if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale); 66 67 if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) || 68 scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) { 69 return ViewCompat.LAYOUT_DIRECTION_RTL; 70 } 71 } 72 return ViewCompat.LAYOUT_DIRECTION_LTR; 73 } 74 75 /** 76 * Fallback algorithm to detect the locale direction. Rely on the first char of the 77 * localized locale name. This will not work if the localized locale name is in English 78 * (this is the case for ICU 4.4 and "Urdu" script) 79 * 80 * @param locale 81 * @return the layout direction. This may be one of: 82 * {@link ViewCompat#LAYOUT_DIRECTION_LTR} or 83 * {@link ViewCompat#LAYOUT_DIRECTION_RTL}. 84 * 85 * Be careful: this code will need to be updated when vertical scripts will be supported 86 */ 87 private static int getLayoutDirectionFromFirstChar(@NonNull Locale locale) { 88 switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) { 89 case Character.DIRECTIONALITY_RIGHT_TO_LEFT: 90 case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC: 91 return ViewCompat.LAYOUT_DIRECTION_RTL; 92 93 case Character.DIRECTIONALITY_LEFT_TO_RIGHT: 94 default: 95 return ViewCompat.LAYOUT_DIRECTION_LTR; 96 } 97 } 98 } 99 100 private static class TextUtilsCompatJellybeanMr1Impl extends TextUtilsCompatImpl { 101 @Override 102 @NonNull 103 public String htmlEncode(@NonNull String s) { 104 return TextUtilsCompatJellybeanMr1.htmlEncode(s); 105 } 106 107 @Override 108 public int getLayoutDirectionFromLocale(@Nullable Locale locale) { 109 return TextUtilsCompatJellybeanMr1.getLayoutDirectionFromLocale(locale); 110 } 111 } 112 113 private static final TextUtilsCompatImpl IMPL; 114 static { 115 final int version = Build.VERSION.SDK_INT; 116 if (version >= 17) { // JellyBean MR1 117 IMPL = new TextUtilsCompatJellybeanMr1Impl(); 118 } else { 119 IMPL = new TextUtilsCompatImpl(); 120 } 121 } 122 123 /** 124 * Html-encode the string. 125 * @param s the string to be encoded 126 * @return the encoded string 127 */ 128 @NonNull 129 public static String htmlEncode(@NonNull String s) { 130 return IMPL.htmlEncode(s); 131 } 132 133 /** 134 * Return the layout direction for a given Locale 135 * 136 * @param locale the Locale for which we want the layout direction. Can be null. 137 * @return the layout direction. This may be one of: 138 * {@link ViewCompat#LAYOUT_DIRECTION_LTR} or 139 * {@link ViewCompat#LAYOUT_DIRECTION_RTL}. 140 * 141 * Be careful: this code will need to be updated when vertical scripts will be supported 142 */ 143 public static int getLayoutDirectionFromLocale(@Nullable Locale locale) { 144 return IMPL.getLayoutDirectionFromLocale(locale); 145 } 146 147 public static final Locale ROOT = new Locale("", ""); 148 149 private static String ARAB_SCRIPT_SUBTAG = "Arab"; 150 private static String HEBR_SCRIPT_SUBTAG = "Hebr"; 151 152 private TextUtilsCompat() {} 153} 154