Binding.java revision e52882df6130221462bf07f5f2b52de5c4b0f8de
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.Expr; 20import android.databinding.tool.processing.ErrorMessages; 21import android.databinding.tool.processing.Scope; 22import android.databinding.tool.processing.scopes.LocationScopeProvider; 23import android.databinding.tool.reflection.ModelAnalyzer; 24import android.databinding.tool.reflection.ModelClass; 25import android.databinding.tool.store.Location; 26import android.databinding.tool.store.SetterStore; 27import android.databinding.tool.store.SetterStore.SetterCall; 28import android.databinding.tool.util.L; 29import android.databinding.tool.writer.WriterPackage; 30 31import java.util.List; 32 33public class Binding implements LocationScopeProvider { 34 35 private final String mName; 36 private final Expr mExpr; 37 private final BindingTarget mTarget; 38 private SetterStore.SetterCall mSetterCall; 39 40 public Binding(BindingTarget target, String name, Expr expr) { 41 mTarget = target; 42 mName = name; 43 mExpr = expr; 44 } 45 46 @Override 47 public List<Location> provideScopeLocation() { 48 return mExpr.getLocations(); 49 } 50 51 public void resolveListeners() { 52 ModelClass listenerParameter = getListenerParameter(); 53 if (listenerParameter != null) { 54 mExpr.resolveListeners(listenerParameter); 55 } 56 } 57 58 private SetterStore.BindingSetterCall getSetterCall() { 59 if (mSetterCall == null) { 60 try { 61 Scope.enter(getTarget()); 62 Scope.enter(this); 63 resolveSetterCall(); 64 if (mSetterCall == null) { 65 L.e(ErrorMessages.CANNOT_FIND_SETTER_CALL, mName, mExpr.getResolvedType()); 66 } 67 } finally { 68 Scope.exit(); 69 Scope.exit(); 70 } 71 } 72 return mSetterCall; 73 } 74 75 private void resolveSetterCall() { 76 ModelClass viewType = mTarget.getResolvedType(); 77 if (viewType != null && viewType.extendsViewStub()) { 78 if (isListenerAttribute()) { 79 ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance(); 80 ModelClass viewStubProxy = modelAnalyzer. 81 findClass("android.databinding.ViewStubProxy", null); 82 mSetterCall = SetterStore.get(modelAnalyzer).getSetterCall(mName, 83 viewStubProxy, mExpr.getResolvedType(), mExpr.getModel().getImports()); 84 } else if (isViewStubAttribute()) { 85 mSetterCall = new ViewStubDirectCall(mName, viewType, mExpr); 86 } else { 87 mSetterCall = new ViewStubSetterCall(mName); 88 } 89 } else { 90 mSetterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName, 91 viewType, mExpr.getResolvedType(), mExpr.getModel().getImports()); 92 } 93 } 94 95 /** 96 * Similar to getSetterCall, but assumes an Object parameter to find the best matching listener. 97 */ 98 private ModelClass getListenerParameter() { 99 ModelClass viewType = mTarget.getResolvedType(); 100 SetterCall setterCall; 101 ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance(); 102 ModelClass objectParameter = modelAnalyzer.findClass(Object.class); 103 if (viewType != null && viewType.extendsViewStub()) { 104 if (isListenerAttribute()) { 105 ModelClass viewStubProxy = modelAnalyzer. 106 findClass("android.databinding.ViewStubProxy", null); 107 setterCall = SetterStore.get(modelAnalyzer).getSetterCall(mName, 108 viewStubProxy, objectParameter, mExpr.getModel().getImports()); 109 } else if (isViewStubAttribute()) { 110 setterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName, 111 viewType, objectParameter, mExpr.getModel().getImports()); 112 } else { 113 setterCall = new ViewStubSetterCall(mName); 114 } 115 } else { 116 setterCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(mName, 117 viewType, objectParameter, mExpr.getModel().getImports()); 118 } 119 if (setterCall == null) { 120 return null; 121 } 122 return setterCall.getParameterTypes()[0]; 123 } 124 125 public BindingTarget getTarget() { 126 return mTarget; 127 } 128 129 public String toJavaCode(String targetViewName, String bindingComponent) { 130 final String currentValue = requiresOldValue() 131 ? "this." + WriterPackage.getOldValueName(mExpr) : null; 132 final String argCode = getExpr().toCode().generate(); 133 return getSetterCall().toJava(bindingComponent, targetViewName, currentValue, argCode); 134 } 135 136 public String getBindingAdapterInstanceClass() { 137 return getSetterCall().getBindingAdapterInstanceClass(); 138 } 139 140 public void setBindingAdapterCall(String method) { 141 getSetterCall().setBindingAdapterCall(method); 142 } 143 144 public Expr[] getComponentExpressions() { 145 return new Expr[] { mExpr }; 146 } 147 148 public boolean requiresOldValue() { 149 return getSetterCall().requiresOldValue(); 150 } 151 152 /** 153 * The min api level in which this binding should be executed. 154 * <p> 155 * This should be the minimum value among the dependencies of this binding. For now, we only 156 * check the setter. 157 */ 158 public int getMinApi() { 159 return getSetterCall().getMinApi(); 160 } 161 162 public String getName() { 163 return mName; 164 } 165 166 public Expr getExpr() { 167 return mExpr; 168 } 169 170 private boolean isViewStubAttribute() { 171 return ("android:inflatedId".equals(mName) || 172 "android:layout".equals(mName) || 173 "android:visibility".equals(mName) || 174 "android:layoutInflater".equals(mName)); 175 } 176 177 private boolean isListenerAttribute() { 178 return ("android:onInflate".equals(mName) || 179 "android:onInflateListener".equals(mName)); 180 181 } 182 183 private static class ViewStubSetterCall extends SetterCall { 184 private final String mName; 185 186 public ViewStubSetterCall(String name) { 187 mName = name.substring(name.lastIndexOf(':') + 1); 188 } 189 190 @Override 191 protected String toJavaInternal(String componentExpression, String viewExpression, 192 String converted) { 193 return "if (" + viewExpression + ".isInflated()) " + viewExpression + 194 ".getBinding().setVariable(BR." + mName + ", " + converted + ")"; 195 } 196 197 @Override 198 protected String toJavaInternal(String componentExpression, String viewExpression, 199 String oldValue, String converted) { 200 return null; 201 } 202 203 @Override 204 public int getMinApi() { 205 return 0; 206 } 207 208 @Override 209 public boolean requiresOldValue() { 210 return false; 211 } 212 213 @Override 214 public ModelClass[] getParameterTypes() { 215 return new ModelClass[] { 216 ModelAnalyzer.getInstance().findClass(Object.class) 217 }; 218 } 219 220 @Override 221 public String getBindingAdapterInstanceClass() { 222 return null; 223 } 224 225 @Override 226 public void setBindingAdapterCall(String method) { 227 } 228 } 229 230 private static class ViewStubDirectCall extends SetterCall { 231 private final SetterCall mWrappedCall; 232 233 public ViewStubDirectCall(String name, ModelClass viewType, Expr expr) { 234 mWrappedCall = SetterStore.get(ModelAnalyzer.getInstance()).getSetterCall(name, 235 viewType, expr.getResolvedType(), expr.getModel().getImports()); 236 if (mWrappedCall == null) { 237 L.e("Cannot find the setter for attribute '%s' on %s with parameter type %s.", 238 name, viewType, expr.getResolvedType()); 239 } 240 } 241 242 @Override 243 protected String toJavaInternal(String componentExpression, String viewExpression, 244 String converted) { 245 return "if (!" + viewExpression + ".isInflated()) " + 246 mWrappedCall.toJava(componentExpression, viewExpression + ".getViewStub()", 247 null, converted); 248 } 249 250 @Override 251 protected String toJavaInternal(String componentExpression, String viewExpression, 252 String oldValue, String converted) { 253 return null; 254 } 255 256 @Override 257 public int getMinApi() { 258 return 0; 259 } 260 261 @Override 262 public boolean requiresOldValue() { 263 return false; 264 } 265 266 @Override 267 public ModelClass[] getParameterTypes() { 268 return new ModelClass[] { 269 ModelAnalyzer.getInstance().findClass(Object.class) 270 }; 271 } 272 273 @Override 274 public String getBindingAdapterInstanceClass() { 275 return mWrappedCall.getBindingAdapterInstanceClass(); 276 } 277 278 @Override 279 public void setBindingAdapterCall(String method) { 280 mWrappedCall.setBindingAdapterCall(method); 281 } 282 } 283} 284