1d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount/* 2d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * Copyright (C) 2015 The Android Open Source Project 3d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * 4d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * Licensed under the Apache License, Version 2.0 (the "License"); 5d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * you may not use this file except in compliance with the License. 6d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * You may obtain a copy of the License at 7d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * 8d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * http://www.apache.org/licenses/LICENSE-2.0 9d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * 10d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * Unless required by applicable law or agreed to in writing, software 11d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * distributed under the License is distributed on an "AS IS" BASIS, 12d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * See the License for the specific language governing permissions and 14d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * limitations under the License. 15d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount */ 16d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 17d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountpackage android.databinding.tool; 18d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 19d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.expr.Expr; 20d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.expr.ExprModel; 21d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.expr.FieldAccessExpr; 22d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.processing.ErrorMessages; 23d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.processing.Scope; 24d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.processing.scopes.LocationScopeProvider; 25d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.reflection.ModelAnalyzer; 26d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.reflection.ModelClass; 27d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.Location; 28d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.SetterStore; 29d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.SetterStore.BindingGetterCall; 30d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.SetterStore.BindingSetterCall; 31d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.util.L; 32d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.util.Preconditions; 33d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.writer.FlagSet; 34d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.writer.KCode; 35d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.writer.LayoutBinderWriterKt; 36d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 37d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport kotlin.jvm.functions.Function2; 38d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 39d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport java.util.ArrayList; 40d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport java.util.List; 41d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 42d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountpublic class InverseBinding implements LocationScopeProvider { 43d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 44d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private final String mName; 45d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private final Expr mExpr; 46d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private final BindingTarget mTarget; 47d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private BindingGetterCall mGetterCall; 48d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private final ArrayList<FieldAccessExpr> mChainedExpressions = new ArrayList<FieldAccessExpr>(); 49d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 50d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public InverseBinding(BindingTarget target, String name, Expr expr) { 51d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mTarget = target; 52d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mName = name; 53d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mExpr = expr; 54d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 55d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 56d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount @Override 57d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public List<Location> provideScopeLocation() { 58d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (mExpr != null) { 59d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mExpr.getLocations(); 60d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } else { 61d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mChainedExpressions.get(0).getLocations(); 62d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 63d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 64d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 65d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount void setGetterCall(BindingGetterCall getterCall) { 66d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mGetterCall = getterCall; 67d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 68d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 69d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public void addChainedExpression(FieldAccessExpr expr) { 70d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mChainedExpressions.add(expr); 71d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 72d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 73d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public boolean isOnBinder() { 74d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mTarget.getResolvedType().isViewDataBinding(); 75d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 76d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 77d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private SetterStore.BindingGetterCall getGetterCall() { 78d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (mGetterCall == null) { 79d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (mExpr != null) { 80d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mExpr.getResolvedType(); // force resolve of ObservableFields 81d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 82d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount try { 83d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount Scope.enter(mTarget); 84d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount Scope.enter(this); 85d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount resolveGetterCall(); 86d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (mGetterCall == null) { 87d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount L.e(ErrorMessages.CANNOT_FIND_GETTER_CALL, mName, 88d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mExpr == null ? "Unknown" : mExpr.getResolvedType(), 89d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mTarget.getResolvedType()); 90d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 91d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } finally { 92d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount Scope.exit(); 93d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount Scope.exit(); 94d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 95d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 96d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mGetterCall; 97d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 98d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 99d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount private void resolveGetterCall() { 100d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount ModelClass viewType = mTarget.getResolvedType(); 101d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance()); 102d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final ModelClass resolvedType = mExpr == null ? null : mExpr.getResolvedType(); 103d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount mGetterCall = setterStore.getGetterCall(mName, viewType, resolvedType, 104d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount getModel().getImports()); 105d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 106d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 107d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public BindingTarget getTarget() { 108d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mTarget; 109d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 110d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 111d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public KCode toJavaCode(String bindingComponent, final FlagSet flagField) { 112d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final String targetViewName = LayoutBinderWriterKt.getFieldName(getTarget()); 113d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount KCode code = new KCode(); 114d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount // A chained expression will have substituted its chained value for the expression 115d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount // unless the attribute has no expression. Therefore, chaining and expressions are 116d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount // mutually exclusive. 117d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount Preconditions.check((mExpr == null) != mChainedExpressions.isEmpty(), 118d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount "Chained expressions are only against unbound attributes."); 119d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (mExpr != null) { 120d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount code.app("", mExpr.toInverseCode(new KCode(getGetterCall().toJava(bindingComponent, 121d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount targetViewName)))); 122d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } else { // !mChainedExpressions.isEmpty()) 123d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final String fieldName = flagField.getLocalName(); 124d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount FlagSet flagSet = new FlagSet(); 125d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount for (FieldAccessExpr expr : mChainedExpressions) { 126d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount flagSet = flagSet.or(new FlagSet(expr.getId())); 127d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 128d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final FlagSet allFlags = flagSet; 129d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount code.nl(new KCode("synchronized(this) {")); 130d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount code.tab(LayoutBinderWriterKt 131d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .mapOr(flagField, flagSet, new Function2<String, Integer, KCode>() { 132d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount @Override 133d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public KCode invoke(String suffix, Integer index) { 134d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return new KCode(fieldName) 135d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app(suffix) 136d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app(" |= ") 137d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app(LayoutBinderWriterKt.binaryCode(allFlags, index)) 138d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount .app(";"); 139d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 140d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount })); 141d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount code.nl(new KCode("}")); 142d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount code.nl(new KCode("requestRebind()")); 143d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 144d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return code; 145d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 146d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 147d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public String getBindingAdapterInstanceClass() { 148d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return getGetterCall().getBindingAdapterInstanceClass(); 149d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 150d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 151d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount /** 152d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * The min api level in which this binding should be executed. 153d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * <p> 154d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount * This should be the minimum value among the dependencies of this binding. 155d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount */ 156d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public int getMinApi() { 157d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final BindingGetterCall getterCall = getGetterCall(); 158d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return Math.max(getterCall.getMinApi(), getterCall.getEvent().getMinApi()); 159d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 160d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 161d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public BindingSetterCall getEventSetter() { 162d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount final BindingGetterCall getterCall = getGetterCall(); 163d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return getterCall.getEvent(); 164d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 165d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 166d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public String getName() { 167d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mName; 168d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 169d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 170d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public String getEventAttribute() { 171d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return getGetterCall().getEventAttribute(); 172d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 173d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount 174d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount public ExprModel getModel() { 175d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount if (mExpr != null) { 176d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mExpr.getModel(); 177d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 178d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount return mChainedExpressions.get(0).getModel(); 179d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount } 180d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount} 181