SdkUtil.java revision fead9ca09b117136b35bc5bf137340a754f9eddd
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * http://www.apache.org/licenses/LICENSE-2.0 7 * Unless required by applicable law or agreed to in writing, software 8 * distributed under the License is distributed on an "AS IS" BASIS, 9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 * See the License for the specific language governing permissions and 11 * limitations under the License. 12 */ 13 14package android.databinding.tool.reflection; 15 16import com.google.common.base.Preconditions; 17 18import org.w3c.dom.Document; 19import org.w3c.dom.Node; 20import org.w3c.dom.NodeList; 21 22import android.databinding.tool.util.L; 23 24import java.io.File; 25import java.util.HashMap; 26import java.util.Map; 27 28import javax.xml.parsers.DocumentBuilder; 29import javax.xml.parsers.DocumentBuilderFactory; 30import javax.xml.xpath.XPath; 31import javax.xml.xpath.XPathExpressionException; 32import javax.xml.xpath.XPathFactory; 33 34/** 35 * Class that is used for SDK related stuff. 36 * <p> 37 * Must be initialized with the sdk location to work properly 38 */ 39public class SdkUtil { 40 41 static File mSdkPath; 42 43 static ApiChecker mApiChecker; 44 45 static int mMinSdk; 46 47 public static void initialize(int minSdk, File sdkPath) { 48 mSdkPath = sdkPath; 49 mMinSdk = minSdk; 50 mApiChecker = new ApiChecker(new File(sdkPath.getAbsolutePath() 51 + "/platform-tools/api/api-versions.xml")); 52 L.d("SdkUtil init, minSdk: %s", minSdk); 53 } 54 55 public static int getMinApi(ModelClass modelClass) { 56 return mApiChecker.getMinApi(modelClass.getJniDescription(), null); 57 } 58 59 public static int getMinApi(ModelMethod modelMethod) { 60 ModelClass declaringClass = modelMethod.getDeclaringClass(); 61 Preconditions.checkNotNull(mApiChecker, "should've initialized api checker"); 62 while (declaringClass != null) { 63 String classDesc = declaringClass.getJniDescription(); 64 String methodDesc = modelMethod.getJniDescription(); 65 int result = mApiChecker.getMinApi(classDesc, methodDesc); 66 L.d("checking method api for %s, class:%s method:%s. result: %d", modelMethod.getName(), 67 classDesc, methodDesc, result); 68 if (result > 1) { 69 return result; 70 } 71 declaringClass = declaringClass.getSuperclass(); 72 } 73 return 1; 74 } 75 76 private static class ApiChecker { 77 78 private Map<String, Integer> mFullLookup = new HashMap<String, Integer>(); 79 80 private Document mDoc; 81 82 private XPath mXPath; 83 84 public ApiChecker(File apiFile) { 85 try { 86 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 87 DocumentBuilder builder = factory.newDocumentBuilder(); 88 mDoc = builder.parse(apiFile); 89 XPathFactory xPathFactory = XPathFactory.newInstance(); 90 mXPath = xPathFactory.newXPath(); 91 buildFullLookup(); 92 } catch (Throwable t) { 93 L.e(t, "cannot load api descriptions from %s", apiFile); 94 } 95 } 96 97 private void buildFullLookup() throws XPathExpressionException { 98 NodeList allClasses = mDoc.getChildNodes().item(0).getChildNodes(); 99 for (int j = 0; j < allClasses.getLength(); j++) { 100 Node node = allClasses.item(j); 101 if (node.getNodeType() != Node.ELEMENT_NODE || !"class" 102 .equals(node.getNodeName())) { 103 continue; 104 } 105 //L.d("checking node %s", node.getAttributes().getNamedItem("name").getNodeValue()); 106 int classSince = getSince(node); 107 String classDesc = node.getAttributes().getNamedItem("name").getNodeValue(); 108 109 final NodeList childNodes = node.getChildNodes(); 110 for (int i = 0; i < childNodes.getLength(); i++) { 111 Node child = childNodes.item(i); 112 if (child.getNodeType() != Node.ELEMENT_NODE || !"method" 113 .equals(child.getNodeName())) { 114 continue; 115 } 116 int methodSince = getSince(child); 117 int since = Math.max(classSince, methodSince); 118 if (since > SdkUtil.mMinSdk) { 119 String methodDesc = child.getAttributes().getNamedItem("name") 120 .getNodeValue(); 121 String key = cacheKey(classDesc, methodDesc); 122 mFullLookup.put(key, since); 123 } 124 } 125 } 126 } 127 128 public int getMinApi(String classDesc, String methodOrFieldDesc) { 129 if (mDoc == null || mXPath == null) { 130 return 1; 131 } 132 if (classDesc == null || classDesc.isEmpty()) { 133 return 1; 134 } 135 final String key = cacheKey(classDesc, methodOrFieldDesc); 136 Integer since = mFullLookup.get(key); 137 return since == null ? 1 : since; 138 } 139 140 private static String cacheKey(String classDesc, String methodOrFieldDesc) { 141 return classDesc + "~" + methodOrFieldDesc; 142 } 143 144 private static int getSince(Node node) { 145 final Node since = node.getAttributes().getNamedItem("since"); 146 if (since != null) { 147 final String nodeValue = since.getNodeValue(); 148 if (nodeValue != null && !nodeValue.isEmpty()) { 149 try { 150 return Integer.parseInt(nodeValue); 151 } catch (Throwable t) { 152 } 153 } 154 } 155 156 return 1; 157 } 158 } 159} 160