19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* //device/libs/android_runtime/android_text_AndroidCharacter.cpp 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** Copyright 2006, The Android Open Source Project 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 569a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** Licensed under the Apache License, Version 2.0 (the "License"); 669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** you may not use this file except in compliance with the License. 769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** You may obtain a copy of the License at 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** http://www.apache.org/licenses/LICENSE-2.0 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** 1169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** Unless required by applicable law or agreed to in writing, software 1269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** distributed under the License is distributed on an "AS IS" BASIS, 1369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1469a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes** See the License for the specific language governing permissions and 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project** limitations under the License. 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project*/ 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "AndroidUnicode" 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 201fc4d880909362127af9873dbacae1d00eb39d8bJim Huang#include "JNIHelp.h" 2169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes#include "ScopedPrimitiveArray.h" 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/misc.h" 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "utils/Log.h" 25a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root#include "unicode/uchar.h" 26a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 27bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root#define PROPERTY_UNDEFINED (-1) 28bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 29a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root// ICU => JDK mapping 30a9886c580b299984e62303a995bf7b13276b5bc8Kenny Rootstatic int directionality_map[U_CHAR_DIRECTION_COUNT] = { 31a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 0, // U_LEFT_TO_RIGHT (0) => DIRECTIONALITY_LEFT_TO_RIGHT (0) 32a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 1, // U_RIGHT_TO_LEFT (1) => DIRECTIONALITY_RIGHT_TO_LEFT (1) 33a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 3, // U_EUROPEAN_NUMBER (2) => DIRECTIONALITY_EUROPEAN_NUMBER (3) 34a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 4, // U_EUROPEAN_NUMBER_SEPARATOR (3) => DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR (4) 35a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 5, // U_EUROPEAN_NUMBER_TERMINATOR (4) => DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR (5) 36a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 6, // U_ARABIC_NUMBER (5) => DIRECTIONALITY_ARABIC_NUMBER (6) 37a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 7, // U_COMMON_NUMBER_SEPARATOR (6) => DIRECTIONALITY_COMMON_NUMBER_SEPARATOR (7) 38a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 10, // U_BLOCK_SEPARATOR (7) => DIRECTIONALITY_PARAGRAPH_SEPARATOR (10) 39a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 11, // U_SEGMENT_SEPARATOR (8) => DIRECTIONALITY_SEGMENT_SEPARATOR (11) 40a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 12, // U_WHITE_SPACE_NEUTRAL (9) => DIRECTIONALITY_WHITESPACE (12) 41a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 13, // U_OTHER_NEUTRAL (10) => DIRECTIONALITY_OTHER_NEUTRALS (13) 42a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 14, // U_LEFT_TO_RIGHT_EMBEDDING (11) => DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING (14) 43a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 15, // U_LEFT_TO_RIGHT_OVERRIDE (12) => DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE (15) 44a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 2, // U_RIGHT_TO_LEFT_ARABIC (13) => DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC (2) 45a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 16, // U_RIGHT_TO_LEFT_EMBEDDING (14) => DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING (16) 46a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 17, // U_RIGHT_TO_LEFT_OVERRIDE (15) => DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE (17) 47a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 18, // U_POP_DIRECTIONAL_FORMAT (16) => DIRECTIONALITY_POP_DIRECTIONAL_FORMAT (18) 48a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 8, // U_DIR_NON_SPACING_MARK (17) => DIRECTIONALITY_NONSPACING_MARK (8) 49a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root 9, // U_BOUNDARY_NEUTRAL (18) => DIRECTIONALITY_BOUNDARY_NEUTRAL (9) 50a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root}; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectnamespace android { 5369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void getDirectionalities(JNIEnv* env, jobject obj, jcharArray srcArray, jbyteArray destArray, int count) 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 5669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes ScopedCharArrayRO src(env, srcArray); 5769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes if (src.get() == NULL) { 5869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 5969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes } 6069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes ScopedByteArrayRW dest(env, destArray); 6169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes if (dest.get() == NULL) { 6269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (env->GetArrayLength(srcArray) < count || env->GetArrayLength(destArray) < count) { 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); 6769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < count; i++) { 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (src[i] >= 0xD800 && src[i] <= 0xDBFF && 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project i + 1 < count && 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project src[i + 1] >= 0xDC00 && src[i + 1] <= 0xDFFF) { 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int c = 0x00010000 + ((src[i] - 0xD800) << 10) + 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (src[i + 1] & 0x3FF); 76a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root int dir = u_charDirection(c); 77a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT) 78bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root dir = PROPERTY_UNDEFINED; 79a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root else 80a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root dir = directionality_map[dir]; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest[i++] = dir; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest[i] = dir; 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int c = src[i]; 86a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root int dir = u_charDirection(c); 87a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root if (dir < 0 || dir >= U_CHAR_DIRECTION_COUNT) 88bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root dest[i] = PROPERTY_UNDEFINED; 89a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root else 90a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root dest[i] = directionality_map[dir]; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 95bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Rootstatic jint getEastAsianWidth(JNIEnv* env, jobject obj, jchar input) 96bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root{ 97bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root int width = u_getIntPropertyValue(input, UCHAR_EAST_ASIAN_WIDTH); 98bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root if (width < 0 || width >= U_EA_COUNT) 99bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root width = PROPERTY_UNDEFINED; 100bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 101bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root return width; 102bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root} 103bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 104bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Rootstatic void getEastAsianWidths(JNIEnv* env, jobject obj, jcharArray srcArray, 105bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root int start, int count, jbyteArray destArray) 106bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root{ 10769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes ScopedCharArrayRO src(env, srcArray); 10869a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes if (src.get() == NULL) { 10969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 11069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes } 11169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes ScopedByteArrayRW dest(env, destArray); 11269a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes if (dest.get() == NULL) { 11369a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 114bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root } 115bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 116bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root if (start < 0 || start > start + count 117bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root || env->GetArrayLength(srcArray) < (start + count) 118bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root || env->GetArrayLength(destArray) < count) { 119bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); 12069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return; 121bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root } 122bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 123bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root for (int i = 0; i < count; i++) { 124bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root const int srci = start + i; 125bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root if (src[srci] >= 0xD800 && src[srci] <= 0xDBFF && 126bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root i + 1 < count && 127bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root src[srci + 1] >= 0xDC00 && src[srci + 1] <= 0xDFFF) { 128bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root int c = 0x00010000 + ((src[srci] - 0xD800) << 10) + 129bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root (src[srci + 1] & 0x3FF); 130bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH); 131bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root if (width < 0 || width >= U_EA_COUNT) 132bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root width = PROPERTY_UNDEFINED; 133bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 134bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root dest[i++] = width; 135bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root dest[i] = width; 136bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root } else { 137bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root int c = src[srci]; 138bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH); 139bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root if (width < 0 || width >= U_EA_COUNT) 140bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root width = PROPERTY_UNDEFINED; 141bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 142bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root dest[i] = width; 143bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root } 144bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root } 145bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root} 146bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jboolean mirror(JNIEnv* env, jobject obj, jcharArray charArray, int start, int count) 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 14969a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes ScopedCharArrayRW data(env, charArray); 15069a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes if (data.get() == NULL) { 15169a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return false; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 154073a3d56ea7505126469dd9ed4c20a7a8923690dKenny Root if (start < 0 || start > start + count 155073a3d56ea7505126469dd9ed4c20a7a8923690dKenny Root || env->GetArrayLength(charArray) < start + count) { 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); 15769a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes return false; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 160e25071650ee4761c86a1b8323de26a07a0f6ad79Raph Levien bool ret = false; 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = start; i < start + count; i++) { 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // XXX this thinks it knows that surrogates are never mirrored 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int c1 = data[i]; 165a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root int c2 = u_charMirror(c1); 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c1 != c2) { 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project data[i] = c2; 169e25071650ee4761c86a1b8323de26a07a0f6ad79Raph Levien ret = true; 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 172e25071650ee4761c86a1b8323de26a07a0f6ad79Raph Levien return ret; 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jchar getMirror(JNIEnv* env, jobject obj, jchar c) 17669a017bc1d1649350f830dfada5c6ed5eac0b770Elliott Hughes{ 177a9886c580b299984e62303a995bf7b13276b5bc8Kenny Root return u_charMirror(c); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod gMethods[] = { 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "getDirectionalities", "([C[BI)V", 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*) getDirectionalities }, 183bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root { "getEastAsianWidth", "(C)I", 184bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root (void*) getEastAsianWidth }, 185bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root { "getEastAsianWidths", "([CII[B)V", 186bb9a51768d2d9dddbe2394b99a00544a3d144facKenny Root (void*) getEastAsianWidths }, 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "mirror", "([CII)Z", 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*) mirror }, 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "getMirror", "(C)C", 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*) getMirror } 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_text_AndroidCharacter(JNIEnv* env) 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{ 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidCharacter", 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gMethods, NELEM(gMethods)); 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 200