Home | History | Annotate | Download | only in cts
      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 android.text.cts;
     18 
     19 import android.content.Context;
     20 import android.cts.util.NullWebViewUtils;
     21 import android.graphics.Bitmap;
     22 import android.graphics.Canvas;
     23 import android.graphics.Paint;
     24 import android.graphics.Picture;
     25 import android.test.ActivityInstrumentationTestCase2;
     26 import android.view.KeyEvent;
     27 import android.view.Menu;
     28 import android.view.View;
     29 import android.widget.TextView;
     30 import android.widget.EditText;
     31 import android.webkit.cts.WebViewOnUiThread;
     32 
     33 public class EmojiTest extends ActivityInstrumentationTestCase2<EmojiCtsActivity> {
     34 
     35     public EmojiTest() {
     36         super("com.android.cts.text", EmojiCtsActivity.class);
     37     }
     38 
     39     protected void setUp() throws Exception {
     40         super.setUp();
     41     }
     42 
     43     protected void tearDown() throws Exception {
     44         super.tearDown();
     45     }
     46 
     47     /**
     48      * Tests all Emoji are defined in Character class
     49      */
     50     public void testEmojiCodePoints() {
     51         for (int i = 0; i < EmojiConstants.emojiCodePoints.length; i++) {
     52             assertTrue(Character.isDefined(EmojiConstants.emojiCodePoints[i]));
     53         }
     54     }
     55 
     56     /**
     57      * Tests Emoji has different glyph for different meaning characters.
     58      * Test on Canvas, TextView, EditText and WebView
     59      */
     60     public void testEmojiGlyph() {
     61         CaptureCanvas ccanvas = new CaptureCanvas(getInstrumentation().getContext());
     62 
     63         Bitmap mBitmapA, mBitmapB;  // Emoji displayed Bitmaps to compare
     64 
     65         int comparedCodePoints[][] = {   // Emojis should have different characters
     66             {0x1F436, 0x1F435},      // Dog(U+1F436) and Monkey(U+1F435)
     67             {0x26BD, 0x26BE},        // Soccer ball(U+26BD) and Baseball(U+26BE)
     68             {0x1F47B, 0x1F381},      // Ghost(U+1F47B) and wrapped present(U+1F381)
     69             {0x2764, 0x1F494},       // Heavy black heart(U+2764) and broken heart(U+1F494)
     70             {0x1F603, 0x1F33B}       // Smiling face with open mouth(U+1F603) and sunflower(U+1F33B)
     71         };
     72 
     73         for (int i = 0; i < comparedCodePoints.length; i++) {
     74 
     75             mBitmapA = ccanvas.capture(Character.toChars(comparedCodePoints[i][0]));
     76             mBitmapB = ccanvas.capture(Character.toChars(comparedCodePoints[i][1]));
     77 
     78             assertFalse(mBitmapA.sameAs(mBitmapB));
     79 
     80             // cannot reuse CaptureTextView as 2nd setText call throws NullPointerException
     81             CaptureTextView cviewA = new CaptureTextView(getInstrumentation().getContext());
     82             mBitmapA = cviewA.capture(Character.toChars(comparedCodePoints[i][0]));
     83             CaptureTextView cviewB = new CaptureTextView(getInstrumentation().getContext());
     84             mBitmapB = cviewB.capture(Character.toChars(comparedCodePoints[i][1]));
     85 
     86             assertFalse(mBitmapA.sameAs(mBitmapB));
     87 
     88             CaptureEditText cedittextA = new CaptureEditText(getInstrumentation().getContext());
     89             mBitmapA = cedittextA.capture(Character.toChars(comparedCodePoints[i][0]));
     90             CaptureEditText cedittextB = new CaptureEditText(getInstrumentation().getContext());
     91             mBitmapB = cedittextB.capture(Character.toChars(comparedCodePoints[i][1]));
     92 
     93             assertFalse(mBitmapA.sameAs(mBitmapB));
     94 
     95             // Trigger activity bringup so we can determine if a WebView is available on this
     96             // device.
     97             EmojiCtsActivity activity = getActivity();
     98             if (NullWebViewUtils.isWebViewAvailable()) {
     99                 CaptureWebView cwebview = new CaptureWebView(getInstrumentation().getContext());
    100                 mBitmapA = cwebview.capture(Character.toChars(comparedCodePoints[i][0]));
    101                 mBitmapB = cwebview.capture(Character.toChars(comparedCodePoints[i][1]));
    102                 assertFalse(mBitmapA.sameAs(mBitmapB));
    103             }
    104         }
    105     }
    106 
    107     /**
    108      * Tests EditText handles Emoji
    109      */
    110     public void testEmojiEditable() throws Throwable {
    111         int testedCodePoints[] = {
    112             0xAE,    // registered mark
    113             0x2764,    // heavy black heart
    114             0x1F353    // strawberry - surrogate pair sample. Count as two characters.
    115         };
    116 
    117         String origStr, newStr;
    118 
    119         // delete Emoji by sending KEYCODE_DEL
    120         for (int i = 0; i < testedCodePoints.length; i++) {
    121             origStr = "Test character  ";
    122             // cannot reuse CaptureTextView as 2nd setText call throws NullPointerException
    123             final EditText editText = new EditText(getInstrumentation().getContext());
    124             editText.setText(origStr + String.valueOf(Character.toChars(testedCodePoints[i])));
    125 
    126             // confirm the emoji is added.
    127             newStr = editText.getText().toString();
    128             assertEquals(newStr.codePointCount(0, newStr.length()), origStr.length() + 1);
    129 
    130             runTestOnUiThread(new Runnable() {
    131                 public void run() {
    132                     // Delete added character by sending KEYCODE_DEL event
    133                     editText.dispatchKeyEvent(
    134                             new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
    135                 }
    136             });
    137             getInstrumentation().waitForIdleSync();
    138 
    139             newStr = editText.getText().toString();
    140             assertEquals(newStr.codePointCount(0, newStr.length()), origStr.length() + 1);
    141         }
    142     }
    143 
    144     private class CaptureCanvas extends View {
    145 
    146         String mTestStr;
    147         Paint paint = new Paint();
    148 
    149         CaptureCanvas(Context context) {
    150             super(context);
    151         }
    152 
    153         public void onDraw(Canvas canvas) {
    154             if (mTestStr != null) {
    155                 canvas.drawText(mTestStr, 50, 50, paint);
    156             }
    157             return;
    158         }
    159 
    160         Bitmap capture(char c[]) {
    161             mTestStr = String.valueOf(c);
    162             invalidate();
    163 
    164             setDrawingCacheEnabled(true);
    165             measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
    166                     MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    167             layout(0, 0, 200,200);
    168 
    169             Bitmap bitmap = Bitmap.createBitmap(getDrawingCache());
    170             setDrawingCacheEnabled(false);
    171             return bitmap;
    172         }
    173 
    174     }
    175 
    176     private class CaptureTextView extends TextView {
    177 
    178         CaptureTextView(Context context) {
    179             super(context);
    180         }
    181 
    182         Bitmap capture(char c[]) {
    183             setText(String.valueOf(c));
    184 
    185             invalidate();
    186 
    187             setDrawingCacheEnabled(true);
    188             measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
    189                     MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    190             layout(0, 0, 200,200);
    191 
    192             Bitmap bitmap = Bitmap.createBitmap(getDrawingCache());
    193             setDrawingCacheEnabled(false);
    194             return bitmap;
    195         }
    196 
    197     }
    198 
    199     private class CaptureEditText extends EditText {
    200 
    201         CaptureEditText(Context context) {
    202             super(context);
    203         }
    204 
    205         Bitmap capture(char c[]) {
    206             setText(String.valueOf(c));
    207 
    208             invalidate();
    209 
    210             setDrawingCacheEnabled(true);
    211             measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
    212                     MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    213             layout(0, 0, 200,200);
    214 
    215             Bitmap bitmap = Bitmap.createBitmap(getDrawingCache());
    216             setDrawingCacheEnabled(false);
    217             return bitmap;
    218         }
    219 
    220     }
    221 
    222 
    223     private class CaptureWebView {
    224 
    225         WebViewOnUiThread webViewOnUiThread;
    226         Bitmap bitmap;
    227         CaptureWebView(Context context) {
    228             webViewOnUiThread = new WebViewOnUiThread(EmojiTest.this, getActivity().getWebView());
    229         }
    230 
    231         Bitmap capture(char c[]) {
    232 
    233             webViewOnUiThread.loadDataAndWaitForCompletion("<html><body>" + String.valueOf(c) + "</body></html>",
    234                     "text/html; charset=utf-8", "utf-8");
    235             // The Chromium-powered WebView renders asynchronously and there's nothing reliable
    236             // we can easily wait for to be sure that capturePicture will return a fresh frame.
    237             // So, just sleep for a sufficient time.
    238             try {
    239                 Thread.sleep(250);
    240             } catch (InterruptedException e) {
    241                 return null;
    242             }
    243 
    244             Picture picture = webViewOnUiThread.capturePicture();
    245             if (picture == null || picture.getHeight() <= 0 || picture.getWidth() <= 0) {
    246                 return null;
    247             } else {
    248                 bitmap = Bitmap.createBitmap(picture.getWidth(), picture.getHeight(),
    249                         Bitmap.Config.ARGB_8888);
    250                 Canvas canvas = new Canvas(bitmap);
    251                 picture.draw(canvas);
    252             }
    253 
    254             return bitmap;
    255         }
    256 
    257     }
    258 
    259 }
    260 
    261