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 android.databinding.tool.expr.ArgListExpr; 20import android.databinding.tool.expr.Expr; 21import android.databinding.tool.expr.ExprModel; 22import android.databinding.tool.reflection.ModelClass; 23import android.databinding.tool.store.SetterStore; 24import android.databinding.tool.util.L; 25import android.databinding.tool.writer.CodeGenUtil; 26import android.databinding.tool.writer.WriterPackage; 27 28import java.lang.reflect.Array; 29import java.util.ArrayList; 30import java.util.Arrays; 31import java.util.List; 32 33/** 34 * Multiple binding expressions can be evaluated using a single adapter. In those cases, 35 * we replace the Binding with a MergedBinding. 36 */ 37public class MergedBinding extends Binding { 38 private final SetterStore.MultiAttributeSetter mMultiAttributeSetter; 39 public MergedBinding(ExprModel model, SetterStore.MultiAttributeSetter multiAttributeSetter, 40 BindingTarget target, Iterable<Binding> bindings) { 41 super(target, createMergedName(bindings), createArgListExpr(model, bindings)); 42 mMultiAttributeSetter = multiAttributeSetter; 43 } 44 45 private static Expr createArgListExpr(ExprModel model, final Iterable<Binding> bindings) { 46 List<Expr> args = new ArrayList<>(); 47 for (Binding binding : bindings) { 48 args.add(binding.getExpr()); 49 } 50 Expr expr = model.argListExpr(args); 51 expr.setBindingExpression(true); 52 return expr; 53 } 54 55 private static String createMergedName(Iterable<Binding> bindings) { 56 StringBuilder sb = new StringBuilder(); 57 for (Binding binding : bindings) { 58 sb.append(binding.getName()); 59 } 60 return sb.toString(); 61 } 62 63 @Override 64 public void resolveListeners() { 65 ModelClass[] params = mMultiAttributeSetter.getParameterTypes(); 66 List<Expr> expressions = getExpr().getChildren(); 67 for (int i = 0; i < params.length; i++) { 68 expressions.get(i).resolveListeners(params[i]); 69 } 70 } 71 72 public Expr[] getComponentExpressions() { 73 ArgListExpr args = (ArgListExpr) getExpr(); 74 return args.getChildren().toArray(new Expr[args.getChildren().size()]); 75 } 76 77 @Override 78 public String getBindingAdapterInstanceClass() { 79 return mMultiAttributeSetter.getBindingAdapterInstanceClass(); 80 } 81 82 @Override 83 public void setBindingAdapterCall(String method) { 84 mMultiAttributeSetter.setBindingAdapterCall(method); 85 } 86 87 @Override 88 public boolean requiresOldValue() { 89 return mMultiAttributeSetter.requiresOldValue(); 90 } 91 92 @Override 93 public int getMinApi() { 94 return 1; 95 } 96 97 @Override 98 public String toJavaCode(String targetViewName, String bindingComponent) { 99 final ArgListExpr args = (ArgListExpr) getExpr(); 100 final List<String> newValues = new ArrayList<>(); 101 for (Expr expr : args.getChildren()) { 102 newValues.add(CodeGenUtil.Companion.toCode(expr, false).generate()); 103 } 104 final List<String> oldValues; 105 if (requiresOldValue()) { 106 oldValues = new ArrayList<>(); 107 for (Expr expr : args.getChildren()) { 108 oldValues.add("this." + WriterPackage.getOldValueName(expr)); 109 } 110 } else { 111 oldValues = Arrays.asList(new String[args.getChildren().size()]); 112 } 113 final String[] expressions = concat(oldValues, newValues, String.class); 114 L.d("merged binding arg: %s", args.getUniqueKey()); 115 return mMultiAttributeSetter.toJava(bindingComponent, targetViewName, expressions); 116 } 117 118 private static <T> T[] concat(List<T> l1, List<T> l2, Class<T> klass) { 119 List<T> result = new ArrayList<>(); 120 result.addAll(l1); 121 result.addAll(l2); 122 return result.toArray((T[]) Array.newInstance(klass, result.size())); 123 } 124} 125