1 /*
<lambda>null2 * 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
14 package android.databinding.tool.writer
15
16 import android.databinding.tool.Binding
17 import android.databinding.tool.BindingTarget
18 import android.databinding.tool.CallbackWrapper
19 import android.databinding.tool.InverseBinding
20 import android.databinding.tool.LayoutBinder
21 import android.databinding.tool.expr.Expr
22 import android.databinding.tool.expr.ExprModel
23 import android.databinding.tool.expr.FieldAccessExpr
24 import android.databinding.tool.expr.IdentifierExpr
25 import android.databinding.tool.expr.LambdaExpr
26 import android.databinding.tool.expr.ListenerExpr
27 import android.databinding.tool.expr.ResourceExpr
28 import android.databinding.tool.expr.TernaryExpr
29 import android.databinding.tool.expr.localizeGlobalVariables
30 import android.databinding.tool.expr.shouldLocalizeInCallbacks
31 import android.databinding.tool.expr.toCode
32 import android.databinding.tool.ext.androidId
33 import android.databinding.tool.ext.br
34 import android.databinding.tool.ext.joinToCamelCaseAsVar
35 import android.databinding.tool.ext.lazyProp
36 import android.databinding.tool.ext.versionedLazy
37 import android.databinding.tool.processing.ErrorMessages
38 import android.databinding.tool.reflection.ModelAnalyzer
39 import android.databinding.tool.reflection.ModelClass
40 import android.databinding.tool.util.L
41 import android.databinding.tool.util.Preconditions
42 import java.util.ArrayList
43 import java.util.Arrays
44 import java.util.BitSet
45 import java.util.HashMap
46
47 fun String.stripNonJava() = this.split("[^a-zA-Z0-9]".toRegex()).map{ it.trim() }.joinToCamelCaseAsVar()
48
49 enum class Scope {
50 GLOBAL,
51 FIELD,
52 METHOD,
53 FLAG,
54 EXECUTE_PENDING_METHOD,
55 CONSTRUCTOR_PARAM,
56 CALLBACK;
57 companion object {
58 var currentScope = GLOBAL;
59 private val scopeStack = arrayListOf<Scope>()
enternull60 fun enter(scope : Scope) {
61 scopeStack.add(currentScope)
62 currentScope = scope
63 }
64
exitnull65 fun exit() {
66 currentScope = scopeStack.removeAt(scopeStack.size - 1)
67 }
68
resetnull69 fun reset() {
70 scopeStack.clear()
71 currentScope = GLOBAL
72 }
73 }
74 }
75
76 class ExprModelExt {
77 val usedFieldNames = hashMapOf<Scope, MutableSet<String>>();
78 init {
<lambda>null79 Scope.values().forEach { usedFieldNames[it] = hashSetOf<String>() }
80 }
81
82 internal val forceLocalize = hashSetOf<Expr>()
83
84 val localizedFlags = arrayListOf<FlagSet>()
85
localizeFlagnull86 fun localizeFlag(set : FlagSet, name:String) : FlagSet {
87 localizedFlags.add(set)
88 val result = getUniqueName(name, Scope.FLAG, false)
89 set.localName = result
90 return set
91 }
92
getUniqueNamenull93 fun getUniqueName(base : String, scope : Scope, isPublic : kotlin.Boolean) : String {
94 var candidateBase = base
95 if (!isPublic && candidateBase.length > 20) {
96 candidateBase = candidateBase.substring(0, 20);
97 }
98 var candidate = candidateBase
99 if (scope == Scope.CALLBACK || scope == Scope.EXECUTE_PENDING_METHOD) {
100 candidate = candidate.decapitalize()
101 }
102 var i = 0
103 while (usedFieldNames[scope]!!.contains(candidate)) {
104 i ++
105 candidate = candidateBase + i
106 }
107 usedFieldNames[scope]!!.add(candidate)
108 return candidate
109 }
110 }
111
ModelClassnull112 fun ModelClass.defaultValue() = ModelAnalyzer.getInstance().getDefaultValue(toJavaCode())
113 fun ExprModel.getUniqueFieldName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.FIELD, isPublic)
114 fun ExprModel.getUniqueMethodName(base : String, isPublic : kotlin.Boolean) : String = ext.getUniqueName(base, Scope.METHOD, isPublic)
115 fun ExprModel.getConstructorParamName(base : String) : String = ext.getUniqueName(base, Scope.CONSTRUCTOR_PARAM, false)
116 fun ExprModel.localizeFlag(set : FlagSet, base : String) : FlagSet = ext.localizeFlag(set, base)
117
118 val Expr.needsLocalField by lazyProp { expr : Expr ->
119 expr.canBeEvaluatedToAVariable() && !(expr.isVariable() && !expr.isUsed) && (expr.isDynamic || expr is ResourceExpr)
120 }
121
Exprnull122 fun Expr.isForcedToLocalize() = model.ext.forceLocalize.contains(this)
123
124 // not necessarily unique. Uniqueness is solved per scope
125 val BindingTarget.readableName by lazyProp { target: BindingTarget ->
126 if (target.id == null) {
127 "boundView" + indexFromTag(target.tag)
128 } else {
129 target.id.androidId().stripNonJava()
130 }
131 }
132
BindingTargetnull133 fun BindingTarget.superConversion(variable : String) : String {
134 if (resolvedType != null && resolvedType.extendsViewStub()) {
135 return "new android.databinding.ViewStubProxy((android.view.ViewStub) $variable)"
136 } else {
137 return "($interfaceClass) $variable"
138 }
139 }
140
targetnull141 val BindingTarget.fieldName : String by lazyProp { target : BindingTarget ->
142 val name : String
143 val isPublic : kotlin.Boolean
144 if (target.id == null) {
145 name = "m${target.readableName}"
146 isPublic = false
147 } else {
148 name = target.readableName
149 isPublic = true
150 }
151 target.model.getUniqueFieldName(name, isPublic)
152 }
153
targetnull154 val BindingTarget.androidId by lazyProp { target : BindingTarget ->
155 if (target.id.startsWith("@android:id/")) {
156 "android.R.id.${target.id.androidId()}"
157 } else {
158 "R.id.${target.id.androidId()}"
159 }
160 }
161
targetnull162 val BindingTarget.interfaceClass by lazyProp { target : BindingTarget ->
163 if (target.resolvedType != null && target.resolvedType.extendsViewStub()) {
164 "android.databinding.ViewStubProxy"
165 } else {
166 target.interfaceType
167 }
168 }
169
targetnull170 val BindingTarget.constructorParamName by lazyProp { target : BindingTarget ->
171 target.model.getConstructorParamName(target.readableName)
172 }
173
174 // not necessarily unique. Uniqueness is decided per scope
exprnull175 val Expr.readableName by lazyProp { expr : Expr ->
176 val stripped = expr.uniqueKey.stripNonJava()
177 L.d("readableUniqueName for [%s] %s is %s", System.identityHashCode(expr), expr.uniqueKey, stripped)
178 stripped
179 }
180
exprnull181 val Expr.fieldName by lazyProp { expr : Expr ->
182 expr.model.getUniqueFieldName("m${expr.readableName.capitalize()}", false)
183 }
184
inverseBindingnull185 val InverseBinding.fieldName by lazyProp { inverseBinding : InverseBinding ->
186 val targetName = inverseBinding.target.fieldName;
187 val eventName = inverseBinding.eventAttribute.stripNonJava()
188 inverseBinding.model.getUniqueFieldName("$targetName$eventName", false)
189 }
190
exprnull191 val Expr.listenerClassName by lazyProp { expr : Expr ->
192 expr.model.getUniqueFieldName("${expr.resolvedType.simpleName}Impl", false)
193 }
194
exprnull195 val Expr.oldValueName by lazyProp { expr : Expr ->
196 expr.model.getUniqueFieldName("mOld${expr.readableName.capitalize()}", false)
197 }
198
Exprnull199 fun Expr.scopedName() : String = when(Scope.currentScope) {
200 Scope.CALLBACK -> callbackLocalName
201 else -> executePendingLocalName
202 }
203
exprnull204 val Expr.callbackLocalName by lazyProp { expr : Expr ->
205 if(expr.shouldLocalizeInCallbacks()) "${expr.model.ext.getUniqueName(expr.readableName, Scope.CALLBACK, false)}"
206 else expr.toCode().generate()
207 }
208
exprnull209 val Expr.executePendingLocalName by lazyProp { expr : Expr ->
210 if(expr.isDynamic || expr.needsLocalField) "${expr.model.ext.getUniqueName(expr.readableName, Scope.EXECUTE_PENDING_METHOD, false)}"
211 else expr.toCode().generate()
212 }
213
exprnull214 val Expr.setterName by lazyProp { expr : Expr ->
215 expr.model.getUniqueMethodName("set${expr.readableName.capitalize()}", true)
216 }
217
exprnull218 val Expr.onChangeName by lazyProp { expr : Expr ->
219 expr.model.getUniqueMethodName("onChange${expr.readableName.capitalize()}", false)
220 }
221
exprnull222 val Expr.getterName by lazyProp { expr : Expr ->
223 expr.model.getUniqueMethodName("get${expr.readableName.capitalize()}", true)
224 }
225
Exprnull226 fun Expr.isVariable() = this is IdentifierExpr && this.isDynamic
227
228 val Expr.dirtyFlagSet by lazyProp { expr : Expr ->
229 FlagSet(expr.invalidFlags, expr.model.flagBucketCount)
230 }
231
exprnull232 val Expr.invalidateFlagSet by lazyProp { expr : Expr ->
233 FlagSet(expr.id)
234 }
235
exprnull236 val Expr.shouldReadFlagSet by versionedLazy { expr : Expr ->
237 FlagSet(expr.shouldReadFlags, expr.model.flagBucketCount)
238 }
239
exprnull240 val Expr.shouldReadWithConditionalsFlagSet by versionedLazy { expr : Expr ->
241 FlagSet(expr.shouldReadFlagsWithConditionals, expr.model.flagBucketCount)
242 }
243
exprnull244 val Expr.conditionalFlags by lazyProp { expr : Expr ->
245 arrayListOf(FlagSet(expr.getRequirementFlagIndex(false)),
246 FlagSet(expr.getRequirementFlagIndex(true)))
247 }
248
Bindingnull249 fun Binding.toAssignmentCode() : String {
250 val fieldName: String
251 if (this.target.viewClass.
252 equals(this.target.interfaceType)) {
253 fieldName = "this.${this.target.fieldName}"
254 } else {
255 fieldName = "((${this.target.viewClass}) this.${this.target.fieldName})"
256 }
257 return this.toJavaCode(fieldName, "this.mBindingComponent")
258 }
259
layoutBindernull260 val LayoutBinder.requiredComponent by lazyProp { layoutBinder: LayoutBinder ->
261 val requiredFromBindings = layoutBinder.
262 bindingTargets.
263 flatMap { it.bindings }.
264 firstOrNull { it.bindingAdapterInstanceClass != null }?.bindingAdapterInstanceClass
265 val requiredFromInverse = layoutBinder.
266 bindingTargets.
267 flatMap { it.inverseBindings }.
268 firstOrNull { it.bindingAdapterInstanceClass != null }?.bindingAdapterInstanceClass
269 requiredFromBindings ?: requiredFromInverse
270 }
271
getRequirementFlagSetnull272 fun Expr.getRequirementFlagSet(expected : Boolean) : FlagSet = conditionalFlags[if(expected) 1 else 0]
273
274 fun FlagSet.notEmpty(cb : (suffix : String, value : Long) -> Unit) {
275 buckets.withIndex().forEach {
276 if (it.value != 0L) {
277 cb(getWordSuffix(it.index), buckets[it.index])
278 }
279 }
280 }
281
getWordSuffixnull282 fun getWordSuffix(wordIndex : Int) : String {
283 return if(wordIndex == 0) "" else "_$wordIndex"
284 }
285
FlagSetnull286 fun FlagSet.localValue(bucketIndex : Int) =
287 if (localName == null) binaryCode(bucketIndex)
288 else "$localName${getWordSuffix(bucketIndex)}"
289
290 fun FlagSet.binaryCode(bucketIndex : Int) = longToBinary(buckets[bucketIndex])
291
292
293 fun longToBinary(l : Long) = "0x${java.lang.Long.toHexString(l)}L"
294
295 fun <T> FlagSet.mapOr(other : FlagSet, cb : (suffix : String, index : Int) -> T) : List<T> {
296 val min = Math.min(buckets.size, other.buckets.size)
297 val result = arrayListOf<T>()
298 for (i in 0..(min - 1)) {
299 // if these two can match by any chance, call the callback
300 if (intersect(other, i)) {
301 result.add(cb(getWordSuffix(i), i))
302 }
303 }
304 return result
305 }
306
indexFromTagnull307 fun indexFromTag(tag : String) : kotlin.Int {
308 val startIndex : kotlin.Int
309 if (tag.startsWith("binding_")) {
310 startIndex = "binding_".length;
311 } else {
312 startIndex = tag.lastIndexOf('_') + 1
313 }
314 return Integer.parseInt(tag.substring(startIndex))
315 }
316
317 class LayoutBinderWriter(val layoutBinder : LayoutBinder) {
318 val model = layoutBinder.model
319 val indices = HashMap<BindingTarget, kotlin.Int>()
<lambda>null320 val mDirtyFlags by lazy {
321 val fs = FlagSet(BitSet(), model.flagBucketCount);
322 Arrays.fill(fs.buckets, -1)
323 fs.isDynamic = true
324 model.localizeFlag(fs, "mDirtyFlags")
325 fs
326 }
327
328 val className = layoutBinder.implementationName
329
330 val baseClassName = "${layoutBinder.className}"
331
<lambda>null332 val includedBinders by lazy {
333 layoutBinder.bindingTargets.filter { it.isBinder }
334 }
335
<lambda>null336 val variables by lazy {
337 model.exprMap.values.filterIsInstance(IdentifierExpr::class.java).filter { it.isVariable() }
338 }
339
<lambda>null340 val usedVariables by lazy {
341 variables.filter {it.isUsed || it.isIsUsedInCallback }
342 }
343
<lambda>null344 val callbacks by lazy {
345 model.exprMap.values.filterIsInstance(LambdaExpr::class.java)
346 }
347
writenull348 public fun write(minSdk : kotlin.Int) : String {
349 Scope.reset()
350 layoutBinder.resolveWhichExpressionsAreUsed()
351 calculateIndices();
352 return kcode("package ${layoutBinder.`package`};") {
353 nl("import ${layoutBinder.modulePackage}.R;")
354 nl("import ${layoutBinder.modulePackage}.BR;")
355 nl("import android.view.View;")
356 val classDeclaration : String
357 if (layoutBinder.hasVariations()) {
358 classDeclaration = "$className extends $baseClassName"
359 } else {
360 classDeclaration = "$className extends android.databinding.ViewDataBinding"
361 }
362 block("public class $classDeclaration ${buildImplements()}") {
363 nl(declareIncludeViews())
364 nl(declareViews())
365 nl(declareVariables())
366 nl(declareBoundValues())
367 nl(declareListeners())
368 try {
369 Scope.enter(Scope.GLOBAL)
370 nl(declareInverseBindingImpls());
371 } finally {
372 Scope.exit()
373 }
374 nl(declareConstructor(minSdk))
375 nl(declareInvalidateAll())
376 nl(declareHasPendingBindings())
377 nl(declareSetVariable())
378 nl(variableSettersAndGetters())
379 nl(onFieldChange())
380 try {
381 Scope.enter(Scope.GLOBAL)
382 nl(executePendingBindings())
383 } finally {
384 Scope.exit()
385 }
386
387 nl(declareListenerImpls())
388 try {
389 Scope.enter(Scope.CALLBACK)
390 nl(declareCallbackImplementations())
391 } finally {
392 Scope.exit()
393 }
394
395 nl(declareDirtyFlags())
396 if (!layoutBinder.hasVariations()) {
397 nl(declareFactories())
398 }
399 nl(flagMapping())
400 nl("//end")
401 }
402 }.generate()
403 }
buildImplementsnull404 fun buildImplements() : String {
405 return if (callbacks.isEmpty()) {
406 ""
407 } else {
408 "implements " + callbacks.map { it.callbackWrapper.cannonicalListenerName }.distinct().joinToString(", ")
409 }
410 }
411
calculateIndicesnull412 fun calculateIndices() : Unit {
413 val taggedViews = layoutBinder.bindingTargets.filter{
414 it.isUsed && it.tag != null && !it.isBinder
415 }
416 taggedViews.forEach {
417 indices.put(it, indexFromTag(it.tag))
418 }
419 val indexStart = maxIndex() + 1
420 layoutBinder.bindingTargets.filter{
421 it.isUsed && !taggedViews.contains(it)
422 }.withIndex().forEach {
423 indices.put(it.value, it.index + indexStart)
424 }
425 }
<lambda>null426 fun declareIncludeViews() = kcode("") {
427 nl("private static final android.databinding.ViewDataBinding.IncludedLayouts sIncludes;")
428 nl("private static final android.util.SparseIntArray sViewsWithIds;")
429 nl("static {") {
430 val hasBinders = layoutBinder.bindingTargets.firstOrNull{ it.isUsed && it.isBinder } != null
431 if (!hasBinders) {
432 tab("sIncludes = null;")
433 } else {
434 val numBindings = layoutBinder.bindingTargets.filter{ it.isUsed }.count()
435 tab("sIncludes = new android.databinding.ViewDataBinding.IncludedLayouts($numBindings);")
436 val includeMap = HashMap<BindingTarget, ArrayList<BindingTarget>>()
437 layoutBinder.bindingTargets.filter{ it.isUsed && it.isBinder }.forEach {
438 val includeTag = it.tag;
439 val parent = layoutBinder.bindingTargets.firstOrNull {
440 it.isUsed && !it.isBinder && includeTag.equals(it.tag)
441 } ?: throw IllegalStateException("Could not find parent of include file")
442 var list = includeMap[parent]
443 if (list == null) {
444 list = ArrayList<BindingTarget>()
445 includeMap.put(parent, list)
446 }
447 list.add(it)
448 }
449
450 includeMap.keys.forEach {
451 val index = indices[it]
452 tab("sIncludes.setIncludes($index, ") {
453 tab ("new String[] {${
454 includeMap[it]!!.map {
455 "\"${it.includedLayout}\""
456 }.joinToString(", ")
457 }},")
458 tab("new int[] {${
459 includeMap[it]!!.map {
460 "${indices[it]}"
461 }.joinToString(", ")
462 }},")
463 tab("new int[] {${
464 includeMap[it]!!.map {
465 "R.layout.${it.includedLayout}"
466 }.joinToString(", ")
467 }});")
468 }
469 }
470 }
471 val viewsWithIds = layoutBinder.bindingTargets.filter {
472 it.isUsed && !it.isBinder && (!it.supportsTag() || (it.id != null && it.tag == null))
473 }
474 if (viewsWithIds.isEmpty()) {
475 tab("sViewsWithIds = null;")
476 } else {
477 tab("sViewsWithIds = new android.util.SparseIntArray();")
478 viewsWithIds.forEach {
479 tab("sViewsWithIds.put(${it.androidId}, ${indices[it]});")
480 }
481 }
482 }
483 nl("}")
484 }
485
486 fun maxIndex() : kotlin.Int {
487 val maxIndex = indices.values.max()
488 if (maxIndex == null) {
489 return -1
490 } else {
491 return maxIndex
492 }
493 }
494
495 fun declareConstructor(minSdk : kotlin.Int) = kcode("") {
496 val bindingCount = maxIndex() + 1
497 val parameterType : String
498 val superParam : String
499 if (layoutBinder.isMerge) {
500 parameterType = "View[]"
501 superParam = "root[0]"
502 } else {
503 parameterType = "View"
504 superParam = "root"
505 }
506 val rootTagsSupported = minSdk >= 14
507 if (layoutBinder.hasVariations()) {
508 nl("")
509 nl("public $className(android.databinding.DataBindingComponent bindingComponent, $parameterType root) {") {
510 tab("this(bindingComponent, $superParam, mapBindings(bindingComponent, root, $bindingCount, sIncludes, sViewsWithIds));")
511 }
512 nl("}")
513 nl("private $className(android.databinding.DataBindingComponent bindingComponent, $parameterType root, Object[] bindings) {") {
514 tab("super(bindingComponent, $superParam, ${model.observables.size}") {
515 layoutBinder.sortedTargets.filter { it.id != null }.forEach {
516 tab(", ${fieldConversion(it)}")
517 }
518 tab(");")
519 }
520 }
521 } else {
522 nl("public $baseClassName(android.databinding.DataBindingComponent bindingComponent, $parameterType root) {") {
523 tab("super(bindingComponent, $superParam, ${model.observables.size});")
524 tab("final Object[] bindings = mapBindings(bindingComponent, root, $bindingCount, sIncludes, sViewsWithIds);")
525 }
526 }
527 if (layoutBinder.requiredComponent != null) {
528 tab("ensureBindingComponentIsNotNull(${layoutBinder.requiredComponent}.class);")
529 }
530 val taggedViews = layoutBinder.sortedTargets.filter{it.isUsed }
531 taggedViews.forEach {
532 if (!layoutBinder.hasVariations() || it.id == null) {
533 tab("this.${it.fieldName} = ${fieldConversion(it)};")
534 }
535 if (!it.isBinder) {
536 if (it.resolvedType != null && it.resolvedType.extendsViewStub()) {
537 tab("this.${it.fieldName}.setContainingBinding(this);")
538 }
539 if (it.supportsTag() && it.tag != null &&
540 (rootTagsSupported || it.tag.startsWith("binding_"))) {
541 val originalTag = it.originalTag;
542 var tagValue = "null"
543 if (originalTag != null && !originalTag.startsWith("@{")) {
544 tagValue = "\"$originalTag\""
545 if (originalTag.startsWith("@")) {
546 var packageName = layoutBinder.modulePackage
547 if (originalTag.startsWith("@android:")) {
548 packageName = "android"
549 }
550 val slashIndex = originalTag.indexOf('/')
551 val resourceId = originalTag.substring(slashIndex + 1)
552 tagValue = "root.getResources().getString($packageName.R.string.$resourceId)"
553 }
554 }
555 tab("this.${it.fieldName}.setTag($tagValue);")
556 } else if (it.tag != null && !it.tag.startsWith("binding_") &&
557 it.originalTag != null) {
558 L.e(ErrorMessages.ROOT_TAG_NOT_SUPPORTED, it.originalTag)
559 }
560 }
561 }
562 tab("setRootTag(root);")
563 tab(declareCallbackInstances())
564 tab("invalidateAll();");
565 nl("}")
566 }
567
<lambda>null568 fun declareCallbackInstances() = kcode("// listeners") {
569 callbacks.groupBy { it.callbackWrapper.minApi }
570 .forEach {
571 if (it.key > 1) {
572 block("if(getBuildSdkInt() < ${it.key})") {
573 it.value.forEach { lambda ->
574 nl("${lambda.fieldName} = null;")
575 }
576 }
577 block("else") {
578 it.value.forEach { lambda ->
579 nl("${lambda.fieldName} = ${lambda.generateConstructor()};")
580 }
581 }
582 } else {
583 it.value.forEach { lambda ->
584 nl("${lambda.fieldName} = ${lambda.generateConstructor()};")
585 }
586 }
587 }
588 }
589
<lambda>null590 fun declareCallbackImplementations() = kcode("// callback impls") {
591 callbacks.groupBy { it.callbackWrapper }.forEach {
592 val wrapper = it.key
593 val lambdas = it.value
594 val shouldReturn = !wrapper.method.returnType.isVoid
595 if (shouldReturn) {
596 lambdas.forEach {
597 it.callbackExprModel.ext.forceLocalize.add(it.expr)
598 }
599 }
600 block("public final ${wrapper.method.returnType.canonicalName} ${wrapper.listenerMethodName}(${wrapper.allArgsWithTypes()})") {
601 Preconditions.check(lambdas.size > 0, "bindings list should not be empty")
602 if (lambdas.size == 1) {
603 val lambda = lambdas[0]
604 nl(lambda.callbackExprModel.localizeGlobalVariables(lambda))
605 nl(lambda.executionPath.toCode())
606 if (shouldReturn) {
607 nl("return ${lambda.expr.scopedName()};")
608 }
609 } else {
610 block("switch(${CallbackWrapper.SOURCE_ID})") {
611 lambdas.forEach { lambda ->
612 block("case ${lambda.callbackId}:") {
613 nl(lambda.callbackExprModel.localizeGlobalVariables(lambda))
614 nl(lambda.executionPath.toCode())
615 if (shouldReturn) {
616 nl("return ${lambda.expr.scopedName()};")
617 } else {
618 nl("break;")
619 }
620 }
621 }
622 if (shouldReturn) {
623 block("default:") {
624 nl("return ${wrapper.method.returnType.defaultValue()};")
625 }
626 }
627 }
628 }
629 }
630 }
631 }
632
fieldConversionnull633 fun fieldConversion(target : BindingTarget) : String {
634 if (!target.isUsed) {
635 return "null"
636 } else {
637 val index = indices[target] ?: throw IllegalStateException("Unknown binding target")
638 val variableName = "bindings[$index]"
639 return target.superConversion(variableName)
640 }
641 }
642
<lambda>null643 fun declareInvalidateAll() = kcode("") {
644 nl("@Override")
645 block("public void invalidateAll()") {
646 val fs = FlagSet(layoutBinder.model.invalidateAnyBitSet,
647 layoutBinder.model.flagBucketCount);
648 block("synchronized(this)") {
649 for (i in (0..(mDirtyFlags.buckets.size - 1))) {
650 tab("${mDirtyFlags.localValue(i)} = ${fs.localValue(i)};")
651 }
652 }
653 includedBinders.filter{it.isUsed }.forEach { binder ->
654 nl("${binder.fieldName}.invalidateAll();")
655 }
656 nl("requestRebind();");
657 }
658 }
659
<lambda>null660 fun declareHasPendingBindings() = kcode("") {
661 nl("@Override")
662 nl("public boolean hasPendingBindings() {") {
663 if (mDirtyFlags.buckets.size > 0) {
664 tab("synchronized(this) {") {
665 val flagCheck = 0.rangeTo(mDirtyFlags.buckets.size - 1).map {
666 "${mDirtyFlags.localValue(it)} != 0"
667 }.joinToString(" || ")
668 tab("if ($flagCheck) {") {
669 tab("return true;")
670 }
671 tab("}")
672 }
673 tab("}")
674 }
675 includedBinders.filter{it.isUsed }.forEach { binder ->
676 tab("if (${binder.fieldName}.hasPendingBindings()) {") {
677 tab("return true;")
678 }
679 tab("}")
680 }
681 tab("return false;")
682 }
683 nl("}")
684 }
685
declareSetVariablenull686 fun declareSetVariable() = kcode("") {
687 nl("public boolean setVariable(int variableId, Object variable) {") {
688 tab("switch(variableId) {") {
689 usedVariables.forEach {
690 tab ("case ${it.name.br()} :") {
691 tab("${it.setterName}((${it.resolvedType.toJavaCode()}) variable);")
692 tab("return true;")
693 }
694 }
695 val declaredOnly = variables.filter { !it.isUsed && !it.isIsUsedInCallback && it.isDeclared };
696 declaredOnly.forEachIndexed { i, identifierExpr ->
697 tab ("case ${identifierExpr.name.br()} :") {
698 if (i == declaredOnly.size - 1) {
699 tab("return true;")
700 }
701 }
702 }
703 }
704 tab("}")
705 tab("return false;")
706 }
707 nl("}")
708 }
709
<lambda>null710 fun variableSettersAndGetters() = kcode("") {
711 variables.filterNot{ usedVariables.contains(it) }.forEach {
712 nl("public void ${it.setterName}(${it.resolvedType.toJavaCode()} ${it.readableName}) {") {
713 tab("// not used, ignore")
714 }
715 nl("}")
716 nl("")
717 nl("public ${it.resolvedType.toJavaCode()} ${it.getterName}() {") {
718 tab("return ${it.defaultValue};")
719 }
720 nl("}")
721 }
722 usedVariables.forEach {
723 if (it.userDefinedType != null) {
724 block("public void ${it.setterName}(${it.resolvedType.toJavaCode()} ${it.readableName})") {
725 if (it.isObservable) {
726 nl("updateRegistration(${it.id}, ${it.readableName});");
727 }
728 nl("this.${it.fieldName} = ${it.readableName};")
729 // set dirty flags!
730 val flagSet = it.invalidateFlagSet
731 block("synchronized(this)") {
732 mDirtyFlags.mapOr(flagSet) { suffix, index ->
733 nl("${mDirtyFlags.localName}$suffix |= ${flagSet.localValue(index)};")
734 }
735 }
736 // TODO: Remove this condition after releasing version 1.1 of SDK
737 if (ModelAnalyzer.getInstance().findClass("android.databinding.ViewDataBinding", null).isObservable) {
738 nl("notifyPropertyChanged(${it.name.br()});")
739 }
740 nl("super.requestRebind();")
741 }
742 nl("")
743 block("public ${it.resolvedType.toJavaCode()} ${it.getterName}()") {
744 nl("return ${it.fieldName};")
745 }
746 }
747 }
748 }
749
<lambda>null750 fun onFieldChange() = kcode("") {
751 nl("@Override")
752 nl("protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {") {
753 tab("switch (localFieldId) {") {
754 model.observables.forEach {
755 tab("case ${it.id} :") {
756 tab("return ${it.onChangeName}((${it.resolvedType.toJavaCode()}) object, fieldId);")
757 }
758 }
759 }
760 tab("}")
761 tab("return false;")
762 }
763 nl("}")
764 nl("")
765
766 model.observables.forEach {
767 block("private boolean ${it.onChangeName}(${it.resolvedType.toJavaCode()} ${it.readableName}, int fieldId)") {
768 block("switch (fieldId)", {
769 val accessedFields: List<FieldAccessExpr> = it.parents.filterIsInstance(FieldAccessExpr::class.java)
770 accessedFields.filter { it.isUsed && it.hasBindableAnnotations() }
771 .groupBy { it.brName }
772 .forEach {
773 // If two expressions look different but resolve to the same method,
774 // we are not yet able to merge them. This is why we merge their
775 // flags below.
776 block("case ${it.key}:") {
777 block("synchronized(this)") {
778 val flagSet = it.value.foldRight(FlagSet()) { l, r -> l.invalidateFlagSet.or(r) }
779
780 mDirtyFlags.mapOr(flagSet) { suffix, index ->
781 tab("${mDirtyFlags.localValue(index)} |= ${flagSet.localValue(index)};")
782 }
783 }
784 nl("return true;")
785 }
786
787 }
788 block("case ${"".br()}:") {
789 val flagSet = it.invalidateFlagSet
790 block("synchronized(this)") {
791 mDirtyFlags.mapOr(flagSet) { suffix, index ->
792 tab("${mDirtyFlags.localName}$suffix |= ${flagSet.localValue(index)};")
793 }
794 }
795 nl("return true;")
796 }
797 })
798 nl("return false;")
799 }
800 nl("")
801 }
802 }
803
<lambda>null804 fun declareViews() = kcode("// views") {
805 val oneLayout = !layoutBinder.hasVariations();
806 layoutBinder.sortedTargets.filter {it.isUsed && (oneLayout || it.id == null)}.forEach {
807 val access : String
808 if (oneLayout && it.id != null) {
809 access = "public"
810 } else {
811 access = "private"
812 }
813 nl("$access final ${it.interfaceClass} ${it.fieldName};")
814 }
815 }
816
<lambda>null817 fun declareVariables() = kcode("// variables") {
818 usedVariables.forEach {
819 nl("private ${it.resolvedType.toJavaCode()} ${it.fieldName};")
820 }
821 callbacks.forEach {
822 val wrapper = it.callbackWrapper
823 nl("private final ${wrapper.klass.canonicalName} ${it.fieldName}").app(";")
824 }
825 }
826
<lambda>null827 fun declareBoundValues() = kcode("// values") {
828 layoutBinder.sortedTargets.filter { it.isUsed }
829 .flatMap { it.bindings }
830 .filter { it.requiresOldValue() }
831 .flatMap{ it.componentExpressions.toList() }
832 .groupBy { it }
833 .forEach {
834 val expr = it.key
835 nl("private ${expr.resolvedType.toJavaCode()} ${expr.oldValueName};")
836 }
837 }
838
<lambda>null839 fun declareListeners() = kcode("// listeners") {
840 model.exprMap.values.filter {
841 it is ListenerExpr
842 }.groupBy { it }.forEach {
843 val expr = it.key as ListenerExpr
844 nl("private ${expr.listenerClassName} ${expr.fieldName};")
845 }
846 }
847
<lambda>null848 fun declareInverseBindingImpls() = kcode("// Inverse Binding Event Handlers") {
849 layoutBinder.sortedTargets.filter { it.isUsed }.forEach { target ->
850 target.inverseBindings.forEach { inverseBinding ->
851 val className : String
852 val param : String
853 if (inverseBinding.isOnBinder) {
854 className = "android.databinding.ViewDataBinding.PropertyChangedInverseListener"
855 param = "BR.${inverseBinding.eventAttribute}"
856 } else {
857 className = "android.databinding.InverseBindingListener"
858 param = ""
859 }
860 block("private $className ${inverseBinding.fieldName} = new $className($param)") {
861 nl("@Override")
862 block("public void onChange()") {
863 if (inverseBinding.inverseExpr != null) {
864 val valueExpr = inverseBinding.variableExpr
865 val getterCall = inverseBinding.getterCall
866 nl("// Inverse of ${inverseBinding.expr}")
867 nl("// is ${inverseBinding.inverseExpr}")
868 nl("${valueExpr.resolvedType.toJavaCode()} ${valueExpr.name} = ${getterCall.toJava("mBindingComponent", target.fieldName)};")
869 nl(inverseBinding.callbackExprModel.localizeGlobalVariables(valueExpr))
870 nl(inverseBinding.executionPath.toCode())
871 } else {
872 block("synchronized(this)") {
873 val flagSet = inverseBinding.chainedExpressions.fold(FlagSet(), { initial, expr ->
874 initial.or(FlagSet(expr.id))
875 })
876 mDirtyFlags.mapOr(flagSet) { suffix, index ->
877 tab("${mDirtyFlags.localValue(index)} |= ${flagSet.binaryCode(index)};")
878 }
879 }
880 nl("requestRebind();")
881 }
882 }
883 }.app(";")
884 }
885 }
886 }
<lambda>null887 fun declareDirtyFlags() = kcode("// dirty flag") {
888 model.ext.localizedFlags.forEach { flag ->
889 flag.notEmpty { suffix, value ->
890 nl("private")
891 app(" ", if(flag.isDynamic) null else "static final");
892 app(" ", " ${flag.type} ${flag.localName}$suffix = ${longToBinary(value)};")
893 }
894 }
895 }
896
<lambda>null897 fun flagMapping() = kcode("/* flag mapping") {
898 if (model.flagMapping != null) {
899 val mapping = model.flagMapping
900 for (i in mapping.indices) {
901 tab("flag $i (${longToBinary(1L + i)}): ${model.findFlagExpression(i)}")
902 }
903 }
904 nl("flag mapping end*/")
905 }
906
<lambda>null907 fun executePendingBindings() = kcode("") {
908 nl("@Override")
909 block("protected void executeBindings()") {
910 val tmpDirtyFlags = FlagSet(mDirtyFlags.buckets)
911 tmpDirtyFlags.localName = "dirtyFlags";
912 for (i in (0..mDirtyFlags.buckets.size - 1)) {
913 nl("${tmpDirtyFlags.type} ${tmpDirtyFlags.localValue(i)} = 0;")
914 }
915 block("synchronized(this)") {
916 for (i in (0..mDirtyFlags.buckets.size - 1)) {
917 nl("${tmpDirtyFlags.localValue(i)} = ${mDirtyFlags.localValue(i)};")
918 nl("${mDirtyFlags.localValue(i)} = 0;")
919 }
920 }
921 model.pendingExpressions.filter { it.needsLocalField }.forEach {
922 nl("${it.resolvedType.toJavaCode()} ${it.executePendingLocalName} = ${if (it.isVariable()) it.fieldName else it.defaultValue};")
923 }
924 L.d("writing executePendingBindings for %s", className)
925 do {
926 val batch = ExprModel.filterShouldRead(model.pendingExpressions)
927 val justRead = arrayListOf<Expr>()
928 L.d("batch: %s", batch)
929 while (!batch.none()) {
930 val readNow = batch.filter { it.shouldReadNow(justRead) }
931 if (readNow.isEmpty()) {
932 throw IllegalStateException("do not know what I can read. bailing out ${batch.joinToString("\n")}")
933 }
934 L.d("new read now. batch size: %d, readNow size: %d", batch.size, readNow.size)
935 nl(readWithDependants(readNow, justRead, batch, tmpDirtyFlags))
936 batch.removeAll(justRead)
937 }
938 nl("// batch finished")
939 } while (model.markBitsRead())
940 // verify everything is read.
941 val batch = ExprModel.filterShouldRead(model.pendingExpressions)
942 if (batch.isNotEmpty()) {
943 L.e("could not generate code for %s. This might be caused by circular dependencies."
944 + "Please report on b.android.com. %d %s %s", layoutBinder.layoutname,
945 batch.size, batch[0], batch[0].toCode().generate())
946 }
947 //
948 layoutBinder.sortedTargets.filter { it.isUsed }
949 .flatMap { it.bindings }
950 .groupBy {
951 "${tmpDirtyFlags.mapOr(it.expr.dirtyFlagSet) { suffix, index ->
952 "(${tmpDirtyFlags.localValue(index)} & ${it.expr.dirtyFlagSet.localValue(index)}) != 0"
953 }.joinToString(" || ") }"
954 }.forEach {
955 block("if (${it.key})") {
956 it.value.groupBy { Math.max(1, it.minApi) }.forEach {
957 val setterValues = kcode("") {
958 it.value.forEach { binding ->
959 nl(binding.toAssignmentCode()).app(";")
960 }
961 }
962 nl("// api target ${it.key}")
963 if (it.key > 1) {
964 block("if(getBuildSdkInt() >= ${it.key})") {
965 nl(setterValues)
966 }
967 } else {
968 nl(setterValues)
969 }
970 }
971 }
972 }
973
974
975 layoutBinder.sortedTargets.filter { it.isUsed }
976 .flatMap { it.bindings }
977 .filter { it.requiresOldValue() }
978 .groupBy {"${tmpDirtyFlags.mapOr(it.expr.dirtyFlagSet) { suffix, index ->
979 "(${tmpDirtyFlags.localValue(index)} & ${it.expr.dirtyFlagSet.localValue(index)}) != 0"
980 }.joinToString(" || ")
981 }"}.forEach {
982 block("if (${it.key})") {
983 it.value.groupBy { it.expr }.map { it.value.first() }.forEach {
984 it.componentExpressions.forEach { expr ->
985 nl("this.${expr.oldValueName} = ${expr.toCode().generate()};")
986 }
987 }
988 }
989 }
990 includedBinders.filter{it.isUsed }.forEach { binder ->
991 nl("${binder.fieldName}.executePendingBindings();")
992 }
993 layoutBinder.sortedTargets.filter{
994 it.isUsed && it.resolvedType != null && it.resolvedType.extendsViewStub()
995 }.forEach {
996 block("if (${it.fieldName}.getBinding() != null)") {
997 nl("${it.fieldName}.getBinding().executePendingBindings();")
998 }
999 }
1000 }
1001 }
1002
readWithDependantsnull1003 fun readWithDependants(expressionList: List<Expr>, justRead: MutableList<Expr>,
1004 batch: MutableList<Expr>, tmpDirtyFlags: FlagSet,
1005 inheritedFlags: FlagSet? = null) : KCode = kcode("") {
1006 expressionList.groupBy { it.shouldReadFlagSet }.forEach {
1007 val flagSet = it.key
1008 val needsIfWrapper = inheritedFlags == null || !flagSet.bitsEqual(inheritedFlags)
1009 val expressions = it.value
1010 val ifClause = "if (${tmpDirtyFlags.mapOr(flagSet){ suffix, index ->
1011 "(${tmpDirtyFlags.localValue(index)} & ${flagSet.localValue(index)}) != 0"
1012 }.joinToString(" || ")
1013 })"
1014 val readCode = kcode("") {
1015 val dependants = ArrayList<Expr>()
1016 expressions.groupBy { condition(it) }.forEach {
1017 val condition = it.key
1018 val assignedValues = it.value.filter { it.needsLocalField && !it.isVariable() }
1019 if (!assignedValues.isEmpty()) {
1020 val assignment = kcode("") {
1021 assignedValues.forEach { expr: Expr ->
1022 tab("// read ${expr}")
1023 tab("${expr.executePendingLocalName}").app(" = ", expr.toFullCode()).app(";")
1024 }
1025 }
1026 if (condition != null) {
1027 tab("if ($condition) {") {
1028 app("", assignment)
1029 }
1030 tab ("}")
1031 } else {
1032 app("", assignment)
1033 }
1034 it.value.filter { it.isObservable }.forEach { expr: Expr ->
1035 tab("updateRegistration(${expr.id}, ${expr.executePendingLocalName});")
1036 }
1037 }
1038
1039 it.value.forEach { expr: Expr ->
1040 justRead.add(expr)
1041 L.d("%s / readWithDependants %s", className, expr);
1042 L.d("flag set:%s . inherited flags: %s. need another if: %s", flagSet, inheritedFlags, needsIfWrapper);
1043
1044 // if I am the condition for an expression, set its flag
1045 expr.dependants.filter {
1046 !it.isConditional && it.dependant is TernaryExpr &&
1047 (it.dependant as TernaryExpr).pred == expr
1048 }.map { it.dependant }.groupBy {
1049 // group by when those ternaries will be evaluated (e.g. don't set conditional flags for no reason)
1050 val ternaryBitSet = it.shouldReadFlagsWithConditionals
1051 val isBehindTernary = ternaryBitSet.nextSetBit(model.invalidateAnyFlagIndex) == -1
1052 if (!isBehindTernary) {
1053 val ternaryFlags = it.shouldReadWithConditionalsFlagSet
1054 "if(${tmpDirtyFlags.mapOr(ternaryFlags){ suffix, index ->
1055 "(${tmpDirtyFlags.localValue(index)} & ${ternaryFlags.localValue(index)}) != 0"
1056 }.joinToString(" || ")}) {"
1057 } else {
1058 // TODO if it is behind a ternary, we should set it when its predicate is elevated
1059 // Normally, this would mean that there is another code path to re-read our current expression.
1060 // Unfortunately, this may not be true due to the coverage detection in `expr#markAsReadIfDone`, this may never happen.
1061 // for v1.0, we'll go with always setting it and suffering an unnecessary calculation for this edge case.
1062 // we can solve this by listening to elevation events from the model.
1063 ""
1064 }
1065 }.forEach {
1066 val hasAnotherIf = it.key != ""
1067 if (hasAnotherIf) {
1068 tab(it.key) {
1069 tab("if (${expr.executePendingLocalName}) {") {
1070 it.value.forEach {
1071 val set = it.getRequirementFlagSet(true)
1072 mDirtyFlags.mapOr(set) { suffix, index ->
1073 tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
1074 }
1075 }
1076 }
1077 tab("} else {") {
1078 it.value.forEach {
1079 val set = it.getRequirementFlagSet(false)
1080 mDirtyFlags.mapOr(set) { suffix, index ->
1081 tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
1082 }
1083 }
1084 }.tab("}")
1085 }.app("}")
1086 } else {
1087 tab("if (${expr.executePendingLocalName}) {") {
1088 it.value.forEach {
1089 val set = it.getRequirementFlagSet(true)
1090 mDirtyFlags.mapOr(set) { suffix, index ->
1091 tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
1092 }
1093 }
1094 }
1095 tab("} else {") {
1096 it.value.forEach {
1097 val set = it.getRequirementFlagSet(false)
1098 mDirtyFlags.mapOr(set) { suffix, index ->
1099 tab("${tmpDirtyFlags.localValue(index)} |= ${set.localValue(index)};")
1100 }
1101 }
1102 } app("}")
1103 }
1104 }
1105 val chosen = expr.dependants.filter {
1106 val dependant = it.dependant
1107 batch.contains(dependant) &&
1108 dependant.shouldReadFlagSet.andNot(flagSet).isEmpty &&
1109 dependant.shouldReadNow(justRead)
1110 }
1111 if (chosen.isNotEmpty()) {
1112 dependants.addAll(chosen.map { it.dependant })
1113 }
1114 }
1115 }
1116 if (dependants.isNotEmpty()) {
1117 val nextInheritedFlags = if (needsIfWrapper) flagSet else inheritedFlags
1118 nl(readWithDependants(dependants, justRead, batch, tmpDirtyFlags, nextInheritedFlags))
1119 }
1120 }
1121
1122 if (needsIfWrapper) {
1123 block(ifClause) {
1124 nl(readCode)
1125 }
1126 } else {
1127 nl(readCode)
1128 }
1129 }
1130 }
1131
conditionnull1132 fun condition(expr : Expr) : String? {
1133 if (expr.canBeEvaluatedToAVariable() && !expr.isVariable()) {
1134 // create an if case for all dependencies that might be null
1135 val nullables = expr.dependencies.filter {
1136 it.isMandatory && it.other.resolvedType.isNullable
1137 }.map { it.other }
1138 if (!expr.isEqualityCheck && nullables.isNotEmpty()) {
1139 return "${nullables.map { "${it.executePendingLocalName} != null" }.joinToString(" && ")}"
1140 } else {
1141 return null
1142 }
1143 } else {
1144 return null
1145 }
1146 }
1147
<lambda>null1148 fun declareListenerImpls() = kcode("// Listener Stub Implementations") {
1149 model.exprMap.values.filter {
1150 it.isUsed && it is ListenerExpr
1151 }.groupBy { it }.forEach {
1152 val expr = it.key as ListenerExpr
1153 val listenerType = expr.resolvedType;
1154 val extendsImplements : String
1155 if (listenerType.isInterface) {
1156 extendsImplements = "implements"
1157 } else {
1158 extendsImplements = "extends"
1159 }
1160 nl("public static class ${expr.listenerClassName} $extendsImplements ${listenerType.canonicalName}{") {
1161 if (expr.target.isDynamic) {
1162 tab("private ${expr.target.resolvedType.toJavaCode()} value;")
1163 tab("public ${expr.listenerClassName} setValue(${expr.target.resolvedType.toJavaCode()} value) {") {
1164 tab("this.value = value;")
1165 tab("return value == null ? null : this;")
1166 }
1167 tab("}")
1168 }
1169 val listenerMethod = expr.method
1170 val parameterTypes = listenerMethod.parameterTypes
1171 val returnType = listenerMethod.getReturnType(parameterTypes.toList())
1172 tab("@Override")
1173 tab("public $returnType ${listenerMethod.name}(${
1174 parameterTypes.withIndex().map {
1175 "${it.value.toJavaCode()} arg${it.index}"
1176 }.joinToString(", ")
1177 }) {") {
1178 val obj : String
1179 if (expr.target.isDynamic) {
1180 obj = "this.value"
1181 } else {
1182 obj = expr.target.toCode().generate();
1183 }
1184 val returnStr : String
1185 if (!returnType.isVoid) {
1186 returnStr = "return "
1187 } else {
1188 returnStr = ""
1189 }
1190 val args = parameterTypes.withIndex().map {
1191 "arg${it.index}"
1192 }.joinToString(", ")
1193 tab("$returnStr$obj.${expr.name}($args);")
1194 }
1195 tab("}")
1196 }
1197 nl("}")
1198 }
1199 }
1200
<lambda>null1201 fun declareFactories() = kcode("") {
1202 block("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot)") {
1203 nl("return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());")
1204 }
1205 block("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent)") {
1206 nl("return android.databinding.DataBindingUtil.<$baseClassName>inflate(inflater, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, root, attachToRoot, bindingComponent);")
1207 }
1208 if (!layoutBinder.isMerge) {
1209 block("public static $baseClassName inflate(android.view.LayoutInflater inflater)") {
1210 nl("return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());")
1211 }
1212 block("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent)") {
1213 nl("return bind(inflater.inflate(${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, null, false), bindingComponent);")
1214 }
1215 block("public static $baseClassName bind(android.view.View view)") {
1216 nl("return bind(view, android.databinding.DataBindingUtil.getDefaultComponent());")
1217 }
1218 block("public static $baseClassName bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent)") {
1219 block("if (!\"${layoutBinder.tag}_0\".equals(view.getTag()))") {
1220 nl("throw new RuntimeException(\"view tag isn't correct on view:\" + view.getTag());")
1221 }
1222 nl("return new $baseClassName(bindingComponent, view);")
1223 }
1224 }
1225 }
1226
1227 /**
1228 * When called for a library compilation, we do not generate real implementations
1229 */
writeBaseClassnull1230 public fun writeBaseClass(forLibrary : Boolean) : String =
1231 kcode("package ${layoutBinder.`package`};") {
1232 Scope.reset()
1233 nl("import android.databinding.Bindable;")
1234 nl("import android.databinding.DataBindingUtil;")
1235 nl("import android.databinding.ViewDataBinding;")
1236 nl("public abstract class $baseClassName extends ViewDataBinding {")
1237 layoutBinder.sortedTargets.filter{it.id != null}.forEach {
1238 tab("public final ${it.interfaceClass} ${it.fieldName};")
1239 }
1240 nl("")
1241 tab("protected $baseClassName(android.databinding.DataBindingComponent bindingComponent, android.view.View root_, int localFieldCount") {
1242 layoutBinder.sortedTargets.filter{it.id != null}.forEach {
1243 tab(", ${it.interfaceClass} ${it.constructorParamName}")
1244 }
1245 }
1246 tab(") {") {
1247 tab("super(bindingComponent, root_, localFieldCount);")
1248 layoutBinder.sortedTargets.filter{it.id != null}.forEach {
1249 tab("this.${it.fieldName} = ${it.constructorParamName};")
1250 }
1251 }
1252 tab("}")
1253 nl("")
1254 variables.forEach {
1255 if (it.userDefinedType != null) {
1256 val type = ModelAnalyzer.getInstance().applyImports(it.userDefinedType, model.imports)
1257 tab("public abstract void ${it.setterName}($type ${it.readableName});")
1258 }
1259 }
1260 tab("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot) {") {
1261 tab("return inflate(inflater, root, attachToRoot, android.databinding.DataBindingUtil.getDefaultComponent());")
1262 }
1263 tab("}")
1264 tab("public static $baseClassName inflate(android.view.LayoutInflater inflater) {") {
1265 tab("return inflate(inflater, android.databinding.DataBindingUtil.getDefaultComponent());")
1266 }
1267 tab("}")
1268 tab("public static $baseClassName bind(android.view.View view) {") {
1269 if (forLibrary) {
1270 tab("return null;")
1271 } else {
1272 tab("return bind(view, android.databinding.DataBindingUtil.getDefaultComponent());")
1273 }
1274 }
1275 tab("}")
1276 tab("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.view.ViewGroup root, boolean attachToRoot, android.databinding.DataBindingComponent bindingComponent) {") {
1277 if (forLibrary) {
1278 tab("return null;")
1279 } else {
1280 tab("return DataBindingUtil.<$baseClassName>inflate(inflater, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, root, attachToRoot, bindingComponent);")
1281 }
1282 }
1283 tab("}")
1284 tab("public static $baseClassName inflate(android.view.LayoutInflater inflater, android.databinding.DataBindingComponent bindingComponent) {") {
1285 if (forLibrary) {
1286 tab("return null;")
1287 } else {
1288 tab("return DataBindingUtil.<$baseClassName>inflate(inflater, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname}, null, false, bindingComponent);")
1289 }
1290 }
1291 tab("}")
1292 tab("public static $baseClassName bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) {") {
1293 if (forLibrary) {
1294 tab("return null;")
1295 } else {
1296 tab("return ($baseClassName)bind(bindingComponent, view, ${layoutBinder.modulePackage}.R.layout.${layoutBinder.layoutname});")
1297 }
1298 }
1299 tab("}")
1300 nl("}")
1301 }.generate()
1302 }
1303