19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 22269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackborn * Copyright (C) 2010 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 160dc59e78e18493aecd37427531d093e800846c3eBrett Chabotpackage android.util; 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.test.suitebuilder.annotation.SmallTest; 192269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackbornimport android.util.Patterns; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Matcher; 222269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackborn 232269d1572e5fcfb725ea55f5764d8c3280d69f6dDianne Hackbornimport junit.framework.TestCase; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25ded0e6447ed6e0f200dbca13e43c6cf4efc16a1dDan Egnorpublic class PatternsTest extends TestCase { 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SmallTest 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void testTldPattern() throws Exception { 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean t; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches(); 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Missed valid TLD", t); 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 343ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang // One of the new top level domain. 353ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.TOP_LEVEL_DOMAIN.matcher("me").matches(); 363ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertTrue("Missed valid TLD", t); 373ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang 383ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang // One of the new top level test domain. 393ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches(); 403ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertTrue("Missed valid TLD", t); 413ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang 4252fc810f73e0d8e005281e80a981e1ceed855850Shimeng (Simon) Wang // One of the new top level internationalized domain. 4352fc810f73e0d8e005281e80a981e1ceed855850Shimeng (Simon) Wang t = Patterns.TOP_LEVEL_DOMAIN.matcher("\uD55C\uAD6D").matches(); 4452fc810f73e0d8e005281e80a981e1ceed855850Shimeng (Simon) Wang assertTrue("Missed valid TLD", t); 4552fc810f73e0d8e005281e80a981e1ceed855850Shimeng (Simon) Wang 463ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.TOP_LEVEL_DOMAIN.matcher("mem").matches(); 473ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertFalse("Matched invalid TLD!", t); 483ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang 493ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn").matches(); 503ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertFalse("Matched invalid TLD!", t); 513ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang 52494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.TOP_LEVEL_DOMAIN.matcher("xer").matches(); 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertFalse("Matched invalid TLD!", t); 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SmallTest 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void testUrlPattern() throws Exception { 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean t; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 60494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.WEB_URL.matcher("http://www.google.com").matches(); 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Valid URL", t); 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 633ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang // Google in one of the new top level domain. 643ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("http://www.google.me").matches(); 653ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertTrue("Valid URL", t); 663ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("google.me").matches(); 673ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertTrue("Valid URL", t); 683ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang 693ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d 703ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches(); 713ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertTrue("Valid URL", t); 723ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches(); 733ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang assertTrue("Valid URL", t); 743ed6fbd9e141f20ca382306aa6a355cd544158d1Shimeng (Simon) Wang 75db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang // Url for testing top level Arabic country code domain in Punycode: 76db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang // http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx 77db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches(); 78db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang assertTrue("Valid URL", t); 79db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches(); 80db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang assertTrue("Valid URL", t); 81db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang 8251c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang // Internationalized URL. 8351c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); 8451c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang assertTrue("Valid URL", t); 8551c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); 8651c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang assertTrue("Valid URL", t); 8752fc810f73e0d8e005281e80a981e1ceed855850Shimeng (Simon) Wang // URL with international TLD. 8852fc810f73e0d8e005281e80a981e1ceed855850Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("\uB3C4\uBA54\uC778.\uD55C\uAD6D").matches(); 8952fc810f73e0d8e005281e80a981e1ceed855850Shimeng (Simon) Wang assertTrue("Valid URL", t); 9051c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang 9140064d3098e17eb447e2b9ee4512b691f6b8c269Shimeng (Simon) Wang t = Patterns.WEB_URL.matcher("http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" + 9240064d3098e17eb447e2b9ee4512b691f6b8c269Shimeng (Simon) Wang "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/").matches(); 9340064d3098e17eb447e2b9ee4512b691f6b8c269Shimeng (Simon) Wang assertTrue("Valid URL", t); 9440064d3098e17eb447e2b9ee4512b691f6b8c269Shimeng (Simon) Wang 95494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches(); 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertFalse("Matched invalid protocol", t); 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 98494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches(); 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Didn't match valid URL with port", t); 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 101494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches(); 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Didn't match valid URL with port and query args", t); 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 104494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches(); 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Didn't match valid URL with ~", t); 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SmallTest 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void testIpPattern() throws Exception { 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean t; 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 112494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.IP_ADDRESS.matcher("172.29.86.3").matches(); 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Valid IP", t); 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 115494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.IP_ADDRESS.matcher("1234.4321.9.9").matches(); 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertFalse("Invalid IP", t); 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SmallTest 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void testDomainPattern() throws Exception { 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean t; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 123494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches(); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Valid domain", t); 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 126db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang t = Patterns.DOMAIN_NAME.matcher("google.me").matches(); 12751c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang assertTrue("Valid domain", t); 12851c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang 12951c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang // Internationalized domains. 13051c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); 13151c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang assertTrue("Valid domain", t); 13251c02dbf75fede9b2829af5b821f10e0bc2af124Shimeng (Simon) Wang 133494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches(); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertFalse("Invalid domain", t); 135db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang 136db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang // Obsolete domain .yu 137db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang t = Patterns.DOMAIN_NAME.matcher("test.yu").matches(); 138db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang assertFalse("Obsolete country code top level domain", t); 139db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang 140db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang // Testing top level Arabic country code domain in Punycode: 141db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang t = Patterns.DOMAIN_NAME.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c").matches(); 142db990751ef8e535ea5cb3d527e36936e119095e8Shimeng (Simon) Wang assertTrue("Valid domain", t); 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SmallTest 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void testPhonePattern() throws Exception { 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean t; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 149494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.PHONE.matcher("(919) 555-1212").matches(); 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Valid phone", t); 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 152494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor t = Patterns.PHONE.matcher("2334 9323/54321").matches(); 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertFalse("Invalid phone", t); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] tests = { 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 16505551212 this\n", 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 6505551212 this\n", 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 5551212 this\n", 159a37fc575a4ac40f3ff2e9a9f2108b577a649db73Bin Zhu "Me: 2211 this\n", 160a37fc575a4ac40f3ff2e9a9f2108b577a649db73Bin Zhu "Me: 112 this\n", 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 1-650-555-1212 this\n", 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: (650) 555-1212 this\n", 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: +1 (650) 555-1212 this\n", 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: +1-650-555-1212 this\n", 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 650-555-1212 this\n", 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 555-1212 this\n", 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 1.650.555.1212 this\n", 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: (650) 555.1212 this\n", 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: +1 (650) 555.1212 this\n", 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: +1.650.555.1212 this\n", 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 650.555.1212 this\n", 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 555.1212 this\n", 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 1 650 555 1212 this\n", 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: (650) 555 1212 this\n", 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: +1 (650) 555 1212 this\n", 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: +1 650 555 1212 this\n", 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 650 555 1212 this\n", 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Me: 555 1212 this\n", 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String test : tests) { 185494a1dc5e95e22839b06bf7de84426094a38691aDan Egnor Matcher m = Patterns.PHONE.matcher(test); 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project assertTrue("Valid phone " + test, m.find()); 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 191