LayoutBinder.java revision c96847768305d83c6bc4919432af9bd9bfe4c08e
1/* 2 * Copyright (C) 2015 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 17package android.databinding.tool; 18 19import com.google.common.base.Preconditions; 20 21import android.databinding.tool.expr.Dependency; 22import android.databinding.tool.expr.Expr; 23import android.databinding.tool.expr.ExprModel; 24import android.databinding.tool.expr.IdentifierExpr; 25import android.databinding.tool.store.ResourceBundle; 26import android.databinding.tool.store.ResourceBundle.BindingTargetBundle; 27import android.databinding.tool.writer.LayoutBinderWriter; 28import android.databinding.tool.writer.WriterPackage; 29 30import java.util.ArrayList; 31import java.util.Collections; 32import java.util.Comparator; 33import java.util.HashMap; 34import java.util.List; 35import java.util.Map; 36 37/** 38 * Keeps all information about the bindings per layout file 39 */ 40public class LayoutBinder { 41 private static final Comparator<BindingTarget> COMPARE_FIELD_NAME = new Comparator<BindingTarget>() { 42 @Override 43 public int compare(BindingTarget first, BindingTarget second) { 44 final String fieldName1 = WriterPackage.getFieldName(first); 45 final String fieldName2 = WriterPackage.getFieldName(second); 46 return fieldName1.compareTo(fieldName2); 47 } 48 }; 49 50 /* 51 * val pkg: String, val projectPackage: String, val baseClassName: String, 52 val layoutName:String, val lb: LayoutExprBinding*/ 53 private final ExprModel mExprModel; 54 private final ExpressionParser mExpressionParser; 55 private final List<BindingTarget> mBindingTargets; 56 private final List<BindingTarget> mSortedBindingTargets; 57 private String mModulePackage; 58 private final HashMap<String, String> mUserDefinedVariables = new HashMap<String, String>(); 59 60 private LayoutBinderWriter mWriter; 61 private ResourceBundle.LayoutFileBundle mBundle; 62 private static final String[] sJavaLangClasses = { 63 "Deprecated", 64 "Override", 65 "SafeVarargs", 66 "SuppressWarnings", 67 "Appendable", 68 "AutoCloseable", 69 "CharSequence", 70 "Cloneable", 71 "Comparable", 72 "Iterable", 73 "Readable", 74 "Runnable", 75 "Thread.UncaughtExceptionHandler", 76 "Boolean", 77 "Byte", 78 "Character", 79 "Character.Subset", 80 "Character.UnicodeBlock", 81 "Class", 82 "ClassLoader", 83 "Compiler", 84 "Double", 85 "Enum", 86 "Float", 87 "InheritableThreadLocal", 88 "Integer", 89 "Long", 90 "Math", 91 "Number", 92 "Object", 93 "Package", 94 "Process", 95 "ProcessBuilder", 96 "Runtime", 97 "RuntimePermission", 98 "SecurityManager", 99 "Short", 100 "StackTraceElement", 101 "StrictMath", 102 "String", 103 "StringBuffer", 104 "StringBuilder", 105 "System", 106 "Thread", 107 "ThreadGroup", 108 "ThreadLocal", 109 "Throwable", 110 "Void", 111 "Thread.State", 112 "ArithmeticException", 113 "ArrayIndexOutOfBoundsException", 114 "ArrayStoreException", 115 "ClassCastException", 116 "ClassNotFoundException", 117 "CloneNotSupportedException", 118 "EnumConstantNotPresentException", 119 "Exception", 120 "IllegalAccessException", 121 "IllegalArgumentException", 122 "IllegalMonitorStateException", 123 "IllegalStateException", 124 "IllegalThreadStateException", 125 "IndexOutOfBoundsException", 126 "InstantiationException", 127 "InterruptedException", 128 "NegativeArraySizeException", 129 "NoSuchFieldException", 130 "NoSuchMethodException", 131 "NullPointerException", 132 "NumberFormatException", 133 "ReflectiveOperationException", 134 "RuntimeException", 135 "SecurityException", 136 "StringIndexOutOfBoundsException", 137 "TypeNotPresentException", 138 "UnsupportedOperationException", 139 "AbstractMethodError", 140 "AssertionError", 141 "ClassCircularityError", 142 "ClassFormatError", 143 "Error", 144 "ExceptionInInitializerError", 145 "IllegalAccessError", 146 "IncompatibleClassChangeError", 147 "InstantiationError", 148 "InternalError", 149 "LinkageError", 150 "NoClassDefFoundError", 151 "NoSuchFieldError", 152 "NoSuchMethodError", 153 "OutOfMemoryError", 154 "StackOverflowError", 155 "ThreadDeath", 156 "UnknownError", 157 "UnsatisfiedLinkError", 158 "UnsupportedClassVersionError", 159 "VerifyError", 160 "VirtualMachineError", 161 }; 162 163 public LayoutBinder(ResourceBundle.LayoutFileBundle layoutBundle) { 164 mExprModel = new ExprModel(); 165 mExpressionParser = new ExpressionParser(mExprModel); 166 mBindingTargets = new ArrayList<BindingTarget>(); 167 mBundle = layoutBundle; 168 mModulePackage = layoutBundle.getModulePackage(); 169 // copy over data. 170 for (Map.Entry<String, String> variable : mBundle.getVariables().entrySet()) { 171 addVariable(variable.getKey(), variable.getValue()); 172 } 173 174 for (Map.Entry<String, String> userImport : mBundle.getImports().entrySet()) { 175 mExprModel.addImport(userImport.getKey(), userImport.getValue()); 176 } 177 for (String javaLangClass : sJavaLangClasses) { 178 mExprModel.addImport(javaLangClass, "java.lang." + javaLangClass); 179 } 180 for (BindingTargetBundle targetBundle : mBundle.getBindingTargetBundles()) { 181 final BindingTarget bindingTarget = createBindingTarget(targetBundle); 182 for (ResourceBundle.BindingTargetBundle.BindingBundle bindingBundle : targetBundle 183 .getBindingBundleList()) { 184 bindingTarget.addBinding(bindingBundle.getName(), parse(bindingBundle.getExpr())); 185 } 186 bindingTarget.resolveMultiSetters(); 187 } 188 mSortedBindingTargets = new ArrayList<BindingTarget>(mBindingTargets); 189 Collections.sort(mSortedBindingTargets, COMPARE_FIELD_NAME); 190 } 191 192 public void resolveWhichExpressionsAreUsed() { 193 List<Expr> used = new ArrayList<Expr>(); 194 for (BindingTarget target : mBindingTargets) { 195 for (Binding binding : target.getBindings()) { 196 binding.getExpr().setIsUsed(true); 197 used.add(binding.getExpr()); 198 } 199 } 200 while (!used.isEmpty()) { 201 Expr e = used.remove(used.size() - 1); 202 for (Dependency dep : e.getDependencies()) { 203 if (!dep.getOther().isUsed()) { 204 used.add(dep.getOther()); 205 dep.getOther().setIsUsed(true); 206 } 207 } 208 } 209 } 210 211 public IdentifierExpr addVariable(String name, String type) { 212 Preconditions.checkState(!mUserDefinedVariables.containsKey(name), 213 "%s has already been defined as %s", name, type); 214 final IdentifierExpr id = mExprModel.identifier(name); 215 id.setUserDefinedType(type); 216 id.enableDirectInvalidation(); 217 mUserDefinedVariables.put(name, type); 218 return id; 219 } 220 221 public HashMap<String, String> getUserDefinedVariables() { 222 return mUserDefinedVariables; 223 } 224 225 public BindingTarget createBindingTarget(ResourceBundle.BindingTargetBundle targetBundle) { 226 final BindingTarget target = new BindingTarget(targetBundle); 227 mBindingTargets.add(target); 228 target.setModel(mExprModel); 229 return target; 230 } 231 232 public Expr parse(String input) { 233 final Expr parsed = mExpressionParser.parse(input); 234 parsed.setBindingExpression(true); 235 return parsed; 236 } 237 238 public List<BindingTarget> getBindingTargets() { 239 return mBindingTargets; 240 } 241 242 public List<BindingTarget> getSortedTargets() { 243 return mSortedBindingTargets; 244 } 245 246 public boolean isEmpty() { 247 return mExprModel.size() == 0; 248 } 249 250 public ExprModel getModel() { 251 return mExprModel; 252 } 253 254 private void ensureWriter() { 255 if (mWriter == null) { 256 mWriter = new LayoutBinderWriter(this); 257 } 258 } 259 260 public String writeViewBinderBaseClass() { 261 ensureWriter(); 262 return mWriter.writeBaseClass(); 263 } 264 265 266 public String writeViewBinder(int minSdk) { 267 mExprModel.seal(); 268 ensureWriter(); 269 Preconditions.checkNotNull(getPackage(), "package cannot be null"); 270 Preconditions.checkNotNull(getClassName(), "base class name cannot be null"); 271 return mWriter.write(minSdk); 272 } 273 274 public String getPackage() { 275 return mBundle.getBindingClassPackage(); 276 } 277 278 public boolean isMerge() { 279 return mBundle.isMerge(); 280 } 281 282 public String getModulePackage() { 283 return mModulePackage; 284 } 285 286 public String getLayoutname() { 287 return mBundle.getFileName(); 288 } 289 290 public String getImplementationName() { 291 if (hasVariations()) { 292 return mBundle.getBindingClassName() + mBundle.getConfigName() + "Impl"; 293 } else { 294 return mBundle.getBindingClassName(); 295 } 296 } 297 298 public String getClassName() { 299 return mBundle.getBindingClassName(); 300 } 301 302 public String getTag() { 303 return mBundle.getDirectory() + "/" + mBundle.getFileName(); 304 } 305 306 public boolean hasVariations() { 307 return mBundle.hasVariations(); 308 } 309} 310