Home | History | Annotate | Download | only in tool
      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 
     17 package android.databinding.tool;
     18 
     19 import android.databinding.tool.expr.Expr;
     20 import android.databinding.tool.expr.ExprModel;
     21 import android.databinding.tool.expr.FieldAccessExpr;
     22 import android.databinding.tool.processing.ErrorMessages;
     23 import android.databinding.tool.processing.Scope;
     24 import android.databinding.tool.processing.scopes.LocationScopeProvider;
     25 import android.databinding.tool.reflection.ModelAnalyzer;
     26 import android.databinding.tool.reflection.ModelClass;
     27 import android.databinding.tool.store.Location;
     28 import android.databinding.tool.store.SetterStore;
     29 import android.databinding.tool.store.SetterStore.BindingGetterCall;
     30 import android.databinding.tool.store.SetterStore.BindingSetterCall;
     31 import android.databinding.tool.util.L;
     32 import android.databinding.tool.util.Preconditions;
     33 import android.databinding.tool.writer.FlagSet;
     34 import android.databinding.tool.writer.KCode;
     35 import android.databinding.tool.writer.LayoutBinderWriterKt;
     36 
     37 import kotlin.jvm.functions.Function2;
     38 
     39 import java.util.ArrayList;
     40 import java.util.List;
     41 
     42 public class InverseBinding implements LocationScopeProvider {
     43 
     44     private final String mName;
     45     private final Expr mExpr;
     46     private final BindingTarget mTarget;
     47     private BindingGetterCall mGetterCall;
     48     private final ArrayList<FieldAccessExpr> mChainedExpressions = new ArrayList<FieldAccessExpr>();
     49 
     50     public InverseBinding(BindingTarget target, String name, Expr expr) {
     51         mTarget = target;
     52         mName = name;
     53         mExpr = expr;
     54     }
     55 
     56     @Override
     57     public List<Location> provideScopeLocation() {
     58         if (mExpr != null) {
     59             return mExpr.getLocations();
     60         } else {
     61             return mChainedExpressions.get(0).getLocations();
     62         }
     63     }
     64 
     65     void setGetterCall(BindingGetterCall getterCall) {
     66         mGetterCall = getterCall;
     67     }
     68 
     69     public void addChainedExpression(FieldAccessExpr expr) {
     70         mChainedExpressions.add(expr);
     71     }
     72 
     73     public boolean isOnBinder() {
     74         return mTarget.getResolvedType().isViewDataBinding();
     75     }
     76 
     77     private SetterStore.BindingGetterCall getGetterCall() {
     78         if (mGetterCall == null) {
     79             if (mExpr != null) {
     80                 mExpr.getResolvedType(); // force resolve of ObservableFields
     81             }
     82             try {
     83                 Scope.enter(mTarget);
     84                 Scope.enter(this);
     85                 resolveGetterCall();
     86                 if (mGetterCall == null) {
     87                     L.e(ErrorMessages.CANNOT_FIND_GETTER_CALL, mName,
     88                             mExpr == null ? "Unknown" : mExpr.getResolvedType(),
     89                             mTarget.getResolvedType());
     90                 }
     91             } finally {
     92                 Scope.exit();
     93                 Scope.exit();
     94             }
     95         }
     96         return mGetterCall;
     97     }
     98 
     99     private void resolveGetterCall() {
    100         ModelClass viewType = mTarget.getResolvedType();
    101         final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
    102         final ModelClass resolvedType = mExpr == null ? null : mExpr.getResolvedType();
    103         mGetterCall = setterStore.getGetterCall(mName, viewType, resolvedType,
    104                 getModel().getImports());
    105     }
    106 
    107     public BindingTarget getTarget() {
    108         return mTarget;
    109     }
    110 
    111     public KCode toJavaCode(String bindingComponent, final FlagSet flagField) {
    112         final String targetViewName = LayoutBinderWriterKt.getFieldName(getTarget());
    113         KCode code = new KCode();
    114         // A chained expression will have substituted its chained value for the expression
    115         // unless the attribute has no expression. Therefore, chaining and expressions are
    116         // mutually exclusive.
    117         Preconditions.check((mExpr == null) != mChainedExpressions.isEmpty(),
    118                 "Chained expressions are only against unbound attributes.");
    119         if (mExpr != null) {
    120             code.app("", mExpr.toInverseCode(new KCode(getGetterCall().toJava(bindingComponent,
    121                     targetViewName))));
    122         } else { // !mChainedExpressions.isEmpty())
    123             final String fieldName = flagField.getLocalName();
    124             FlagSet flagSet = new FlagSet();
    125             for (FieldAccessExpr expr : mChainedExpressions) {
    126                 flagSet = flagSet.or(new FlagSet(expr.getId()));
    127             }
    128             final FlagSet allFlags = flagSet;
    129             code.nl(new KCode("synchronized(this) {"));
    130             code.tab(LayoutBinderWriterKt
    131                     .mapOr(flagField, flagSet, new Function2<String, Integer, KCode>() {
    132                         @Override
    133                         public KCode invoke(String suffix, Integer index) {
    134                             return new KCode(fieldName)
    135                                     .app(suffix)
    136                                     .app(" |= ")
    137                                     .app(LayoutBinderWriterKt.binaryCode(allFlags, index))
    138                                     .app(";");
    139                         }
    140                     }));
    141             code.nl(new KCode("}"));
    142             code.nl(new KCode("requestRebind()"));
    143         }
    144         return code;
    145     }
    146 
    147     public String getBindingAdapterInstanceClass() {
    148         return getGetterCall().getBindingAdapterInstanceClass();
    149     }
    150 
    151     /**
    152      * The min api level in which this binding should be executed.
    153      * <p>
    154      * This should be the minimum value among the dependencies of this binding.
    155      */
    156     public int getMinApi() {
    157         final BindingGetterCall getterCall = getGetterCall();
    158         return Math.max(getterCall.getMinApi(), getterCall.getEvent().getMinApi());
    159     }
    160 
    161     public BindingSetterCall getEventSetter() {
    162         final BindingGetterCall getterCall = getGetterCall();
    163         return getterCall.getEvent();
    164     }
    165 
    166     public String getName() {
    167         return mName;
    168     }
    169 
    170     public String getEventAttribute() {
    171         return getGetterCall().getEventAttribute();
    172     }
    173 
    174     public ExprModel getModel() {
    175         if (mExpr != null) {
    176             return mExpr.getModel();
    177         }
    178         return mChainedExpressions.get(0).getModel();
    179     }
    180 }
    181