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