1 /*
2  * Copyright (C) 2014 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 android.text.cts;
18 
19 import static org.junit.Assert.assertTrue;
20 import static org.junit.Assume.assumeTrue;
21 
22 import android.content.Context;
23 import android.content.res.Resources;
24 import android.graphics.Bitmap;
25 import android.graphics.Paint;
26 import android.graphics.fonts.Font;
27 import android.graphics.fonts.SystemFonts;
28 import android.icu.util.ULocale;
29 import android.os.LocaleList;
30 import android.util.TypedValue;
31 import android.widget.TextView;
32 
33 import androidx.test.InstrumentationRegistry;
34 import androidx.test.filters.SmallTest;
35 import androidx.test.runner.AndroidJUnit4;
36 
37 import org.junit.Before;
38 import org.junit.BeforeClass;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 import java.util.Locale;
45 import java.util.Set;
46 
47 @SmallTest
48 @RunWith(AndroidJUnit4.class)
49 public class MyanmarTest {
50 
51     private static final String SCRIPT_QAAG = "Qaag";
52     private static final String SCRIPT_MYMR = "Mymr";
53 
54     /**
55      * The following will be rendered correctly as a single cluster for both Unicode and Zawgyi.
56      */
57     private static final String UNICODE_CORRECT_ORDER = "\u1019\u102d\u102f";
58 
59     /**
60      * The following will not be rendered correctly as a single cluster in Unicode. However it will
61      * render correctly with Zawgyi.
62      */
63     private static final String UNICODE_WRONG_ORDER = "\u1019\u102f\u102d";
64 
65     private static boolean sHasBurmeseLocale;
66     private static List<Locale> sZawgyiLocales = new ArrayList<>();
67     private static List<Locale> sMymrLocales = new ArrayList<>();
68     private Context mContext;
69 
70     @BeforeClass
setupLocales()71     public static void setupLocales() {
72         final String[] supportedLocaleNames = getSupportedLocales();
73         for (String localeName : supportedLocaleNames) {
74             final Locale locale = Locale.forLanguageTag(localeName);
75             final String script = ULocale.addLikelySubtags(ULocale.forLocale(locale)).getScript();
76 
77             if (SCRIPT_QAAG.equals(script)) {
78                 sZawgyiLocales.add(locale);
79             } else if (SCRIPT_MYMR.equals(script)) {
80                 sMymrLocales.add(locale);
81             }
82 
83             sHasBurmeseLocale = (sMymrLocales.size() + sZawgyiLocales.size()) > 0;
84         }
85     }
86 
87     @Before
setupTest()88     public void setupTest() {
89         mContext = InstrumentationRegistry.getTargetContext();
90     }
91 
92     @Test
testIfZawgyiExistsThenUnicodeExists()93     public void testIfZawgyiExistsThenUnicodeExists() {
94         assumeTrue(sHasBurmeseLocale);
95         assumeTrue(!sZawgyiLocales.isEmpty());
96 
97         assertTrue("If the system supports Zawgyi, it should also support Unicode Myanmar",
98                 sMymrLocales.size() > 0);
99     }
100 
101     @Test
testShouldHaveGlyphs()102     public void testShouldHaveGlyphs() {
103         assumeTrue(sHasBurmeseLocale);
104 
105         final Paint paint = new Paint();
106         int index = 0;
107         while (index < UNICODE_CORRECT_ORDER.length()) {
108             int codepoint = UNICODE_CORRECT_ORDER.codePointAt(index);
109 
110             assertTrue("Should have glyph for " + Integer.toHexString(codepoint),
111                     paint.hasGlyph(new String(Character.toChars(codepoint))));
112 
113             index += Character.charCount(codepoint);
114         }
115     }
116 
117     @Test
testMyanmarUnicodeRenders()118     public void testMyanmarUnicodeRenders() {
119         assumeTrue(sHasBurmeseLocale);
120         assumeTrue(!sMymrLocales.isEmpty());
121 
122         assertTrue("Should render Unicode text correctly in Myanmar Unicode locale",
123                 isUnicodeRendersCorrectly(mContext, new LocaleList(sMymrLocales.get(0))));
124     }
125 
126     @Test
testUnicodeRenders_withValidLocaleList()127     public void testUnicodeRenders_withValidLocaleList() {
128         assumeTrue(sHasBurmeseLocale);
129         assumeTrue(!sMymrLocales.isEmpty());
130 
131         final LocaleList[] testLocales = new LocaleList[]{
132                 LocaleList.forLanguageTags("en-Latn-US"),
133                 LocaleList.forLanguageTags("en-Latn"),
134                 LocaleList.forLanguageTags("my-Mymr"),
135                 LocaleList.forLanguageTags("my-Mymr,my-Qaag"),
136                 LocaleList.forLanguageTags("my-Mymr-MM,my-Qaag-MM"),
137                 LocaleList.forLanguageTags("en-Latn,my-Mymr"),
138                 LocaleList.forLanguageTags("en-Latn-US,my-Mymr-MM"),
139                 LocaleList.forLanguageTags("en-Mymr,my-Qaag"),
140                 LocaleList.forLanguageTags("en-Mymr-MM,my-Qaag-MM"),
141         };
142 
143         for (LocaleList localeList : testLocales) {
144             assertTrue("Should render Unicode text correctly in locale " + localeList.toString(),
145                     isUnicodeRendersCorrectly(mContext, localeList));
146         }
147 
148     }
149 
150     @Test
testZawgyiRenders()151     public void testZawgyiRenders() {
152         assumeTrue(sHasBurmeseLocale);
153         assumeTrue(!sZawgyiLocales.isEmpty());
154 
155         assertTrue("Should render Zawgyi text correctly with Zawgyi system locale",
156                 isZawgyiRendersCorrectly(mContext, new LocaleList(sZawgyiLocales.get(0))));
157     }
158 
159     @Test
testZawgyiRenders_withValidLocaleList()160     public void testZawgyiRenders_withValidLocaleList() {
161         assumeTrue(sHasBurmeseLocale);
162         assumeTrue(!sZawgyiLocales.isEmpty());
163 
164         final LocaleList[] testLocales = new LocaleList[]{
165                 LocaleList.forLanguageTags("my-Qaag"),
166                 LocaleList.forLanguageTags("my-Qaag,my-Mymr"),
167                 LocaleList.forLanguageTags("my-Qaag-MM,my-Mymr-MM"),
168                 LocaleList.forLanguageTags("en-Latn,my-Qaag"),
169                 LocaleList.forLanguageTags("en-Latn-US,my-Qaag-MM"),
170                 LocaleList.forLanguageTags("en-Qaag,my-Mymr"),
171                 LocaleList.forLanguageTags("en-Qaag-MM,my-Mymr-MM"),
172         };
173 
174         for (LocaleList localeList : testLocales) {
175             assertTrue("Should render Zawgyi text correctly in locale " + localeList.toString(),
176                     isZawgyiRendersCorrectly(mContext, localeList));
177         }
178     }
179 
180     @Test
testIfZawgyiLocaleIsSupported_fontWithQaagShouldExists()181     public void testIfZawgyiLocaleIsSupported_fontWithQaagShouldExists() {
182         assumeTrue(sHasBurmeseLocale);
183         assumeTrue(!sZawgyiLocales.isEmpty());
184 
185         boolean qaagFontExists = false;
186         final Set<Font> availableFonts = SystemFonts.getAvailableFonts();
187         for (Font font : availableFonts) {
188             final LocaleList localeList = font.getLocaleList();
189             for (int index = 0; index < localeList.size(); index++) {
190                 final Locale fontLocale = localeList.get(index);
191                 final ULocale uLocale = ULocale.addLikelySubtags(ULocale.forLocale(fontLocale));
192                 final String script = uLocale.getScript();
193                 if (SCRIPT_QAAG.equals(script)) {
194                     qaagFontExists = true;
195                     break;
196                 }
197             }
198         }
199 
200         assertTrue(qaagFontExists);
201     }
202 
isUnicodeRendersCorrectly(Context context, LocaleList localeList)203     private static boolean isUnicodeRendersCorrectly(Context context, LocaleList localeList) {
204         final Bitmap bitmapCorrect = CaptureTextView.capture(context, localeList,
205                 UNICODE_CORRECT_ORDER);
206         final Bitmap bitmapWrong = CaptureTextView.capture(context, localeList,
207                 UNICODE_WRONG_ORDER);
208 
209         return !bitmapCorrect.sameAs(bitmapWrong);
210     }
211 
isZawgyiRendersCorrectly(Context context, LocaleList localeList)212     private static boolean isZawgyiRendersCorrectly(Context context, LocaleList localeList) {
213         final Bitmap bitmapCorrect = CaptureTextView.capture(context, localeList,
214                 UNICODE_CORRECT_ORDER);
215         final Bitmap bitmapWrong = CaptureTextView.capture(context, localeList,
216                 UNICODE_WRONG_ORDER);
217 
218         return bitmapCorrect.sameAs(bitmapWrong);
219     }
220 
getSupportedLocales()221     private static String[] getSupportedLocales() {
222         return Resources.getSystem().getStringArray(
223                 Resources.getSystem().getIdentifier("supported_locales", "array", "android"));
224     }
225 
226     private static class CaptureTextView extends TextView {
227 
CaptureTextView(Context context)228         CaptureTextView(Context context) {
229             super(context);
230             final float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 8,
231                     context.getResources().getDisplayMetrics());
232             setTextSize(textSize);
233         }
234 
capture(String text)235         private Bitmap capture(String text) {
236             setText(text);
237 
238             invalidate();
239 
240             setDrawingCacheEnabled(true);
241             measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
242                     MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
243             layout(0, 0, 200, 200);
244 
245             Bitmap bitmap = Bitmap.createBitmap(getDrawingCache());
246             setDrawingCacheEnabled(false);
247             return bitmap;
248         }
249 
capture(Context context, LocaleList localeList, String string)250         static Bitmap capture(Context context, LocaleList localeList, String string) {
251             final CaptureTextView textView = new CaptureTextView(context);
252             if (localeList != null) textView.setTextLocales(localeList);
253             return textView.capture(string);
254         }
255     }
256 
257 }
258