1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage junit.runner; 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.*; 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.*; 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.URL; 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.zip.*; 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * A custom class loader which enables the reloading 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of classes for each test run. The class loader 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * can be configured with a list of package paths that 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * should be excluded from loading. The loading 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * of these packages is delegated to the system class 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * loader. They will be shared across test runs. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p> 16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The list of excluded package paths is specified in 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * a properties file "excluded.properties" that is located in 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the same place as the TestCaseClassLoader class. 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p> 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <b>Known limitation:</b> the TestCaseClassLoader cannot load classes 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * from jar files. 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class TestCaseClassLoader extends ClassLoader { 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** scanned class path */ 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private Vector fPathItems; 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** default excluded paths */ 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private String[] defaultExclusions= { 30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "junit.framework.", 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "junit.extensions.", 32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "junit.runner." 33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project }; 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** name of excluded properties file */ 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project static final String EXCLUDED_FILE= "excluded.properties"; 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** excluded paths */ 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private Vector fExcluded; 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Constructs a TestCaseLoader. It scans the class path 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and the excluded package paths 42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public TestCaseClassLoader() { 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this(System.getProperty("java.class.path")); 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Constructs a TestCaseLoader. It scans the class path 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * and the excluded package paths 50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public TestCaseClassLoader(String classPath) { 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project scanPath(classPath); 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project readExcludedPackages(); 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private void scanPath(String classPath) { 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String separator= System.getProperty("path.separator"); 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fPathItems= new Vector(10); 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project StringTokenizer st= new StringTokenizer(classPath, separator); 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (st.hasMoreTokens()) { 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fPathItems.addElement(st.nextToken()); 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public URL getResource(String name) { 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return ClassLoader.getSystemResource(name); 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public InputStream getResourceAsStream(String name) { 70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return ClassLoader.getSystemResourceAsStream(name); 71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public boolean isExcluded(String name) { 74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i= 0; i < fExcluded.size(); i++) { 75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (name.startsWith((String) fExcluded.elementAt(i))) { 76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public synchronized Class loadClass(String name, boolean resolve) 83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throws ClassNotFoundException { 84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Class c= findLoadedClass(name); 86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (c != null) 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return c; 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Delegate the loading of excluded classes to the 90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // standard class loader. 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (isExcluded(name)) { 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project c= findSystemClass(name); 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return c; 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (ClassNotFoundException e) { 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // keep searching 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (c == null) { 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] data= lookupClassData(name); 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (data == null) 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new ClassNotFoundException(); 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project c= defineClass(name, data, 0, data.length); 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (resolve) 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project resolveClass(c); 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return c; 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private byte[] lookupClassData(String className) throws ClassNotFoundException { 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] data= null; 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i= 0; i < fPathItems.size(); i++) { 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String path= (String) fPathItems.elementAt(i); 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String fileName= className.replace('.', '/')+".class"; 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (isJar(path)) { 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project data= loadJarData(path, fileName); 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project data= loadFileData(path, fileName); 120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (data != null) 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return data; 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new ClassNotFoundException(className); 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project boolean isJar(String pathEntry) { 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return pathEntry.endsWith(".jar") || 129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pathEntry.endsWith(".apk") || 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pathEntry.endsWith(".zip"); 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private byte[] loadFileData(String path, String fileName) { 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project File file= new File(path, fileName); 135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (file.exists()) { 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return getClassData(file); 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private byte[] getClassData(File f) { 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project FileInputStream stream= new FileInputStream(f); 144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ByteArrayOutputStream out= new ByteArrayOutputStream(1000); 145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] b= new byte[1000]; 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int n; 147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while ((n= stream.read(b)) != -1) 148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.write(b, 0, n); 149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stream.close(); 150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.close(); 151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return out.toByteArray(); 152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (IOException e) { 154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private byte[] loadJarData(String path, String fileName) { 159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ZipFile zipFile= null; 160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project InputStream stream= null; 161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project File archive= new File(path); 162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!archive.exists()) 163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zipFile= new ZipFile(archive); 166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch(IOException io) { 167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ZipEntry entry= zipFile.getEntry(fileName); 170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (entry == null) 171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int size= (int) entry.getSize(); 173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stream= zipFile.getInputStream(entry); 175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] data= new byte[size]; 176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int pos= 0; 177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project while (pos < size) { 178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int n= stream.read(data, pos, data.length - pos); 179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project pos += n; 180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project zipFile.close(); 182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return data; 183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (IOException e) { 184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } finally { 185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (stream != null) 187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project stream.close(); 188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (IOException e) { 189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return null; 192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private void readExcludedPackages() { 195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fExcluded= new Vector(10); 196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i= 0; i < defaultExclusions.length; i++) 197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fExcluded.addElement(defaultExclusions[i]); 198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE); 200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (is == null) 201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Properties p= new Properties(); 203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project p.load(is); 205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project catch (IOException e) { 207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } finally { 209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project is.close(); 211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (IOException e) { 212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) { 215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String key= (String)e.nextElement(); 216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (key.startsWith("excluded.")) { 217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String path= p.getProperty(key); 218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project path= path.trim(); 219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (path.endsWith("*")) 220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project path= path.substring(0, path.length()-1); 221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (path.length() > 0) 222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project fExcluded.addElement(path); 223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 227