• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.processing.Scope;
22 import android.databinding.tool.processing.scopes.FileScopeProvider;
23 import android.databinding.tool.processing.scopes.LocationScopeProvider;
24 import android.databinding.tool.reflection.ModelAnalyzer;
25 import android.databinding.tool.reflection.ModelClass;
26 import android.databinding.tool.store.Location;
27 import android.databinding.tool.store.ResourceBundle;
28 import android.databinding.tool.store.SetterStore;
29 import android.databinding.tool.util.L;
30 import android.databinding.tool.util.Preconditions;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 public class BindingTarget implements LocationScopeProvider {
39     List<Binding> mBindings = new ArrayList<Binding>();
40     ExprModel mModel;
41     ModelClass mResolvedClass;
42 
43     // if this target presents itself in multiple layout files with different view types,
44     // it receives an interface type and should use it in the getter instead.
45     private ResourceBundle.BindingTargetBundle mBundle;
46 
BindingTarget(ResourceBundle.BindingTargetBundle bundle)47     public BindingTarget(ResourceBundle.BindingTargetBundle bundle) {
48         mBundle = bundle;
49     }
50 
isUsed()51     public boolean isUsed() {
52         return mBundle.isUsed();
53     }
54 
addBinding(String name, Expr expr)55     public void addBinding(String name, Expr expr) {
56         mBindings.add(new Binding(this, name, expr));
57     }
58 
getInterfaceType()59     public String getInterfaceType() {
60         return mBundle.getInterfaceType() == null ? mBundle.getFullClassName() : mBundle.getInterfaceType();
61     }
62 
63     @Override
provideScopeLocation()64     public List<Location> provideScopeLocation() {
65         return mBundle.provideScopeLocation();
66     }
67 
getId()68     public String getId() {
69         return mBundle.getId();
70     }
71 
getTag()72     public String getTag() {
73         return mBundle.getTag();
74     }
75 
getOriginalTag()76     public String getOriginalTag() {
77         return mBundle.getOriginalTag();
78     }
79 
getViewClass()80     public String getViewClass() {
81         return mBundle.getFullClassName();
82     }
83 
getResolvedType()84     public ModelClass getResolvedType() {
85         if (mResolvedClass == null) {
86             mResolvedClass = ModelAnalyzer.getInstance().findClass(mBundle.getFullClassName(),
87                     mModel.getImports());
88         }
89         return mResolvedClass;
90     }
91 
getIncludedLayout()92     public String getIncludedLayout() {
93         return mBundle.getIncludedLayout();
94     }
95 
isBinder()96     public boolean isBinder() {
97         return getIncludedLayout() != null;
98     }
99 
supportsTag()100     public boolean supportsTag() {
101         return !SetterStore.get(ModelAnalyzer.getInstance())
102                 .isUntaggable(mBundle.getFullClassName());
103     }
104 
getBindings()105     public List<Binding> getBindings() {
106         return mBindings;
107     }
108 
getModel()109     public ExprModel getModel() {
110         return mModel;
111     }
112 
setModel(ExprModel model)113     public void setModel(ExprModel model) {
114         mModel = model;
115     }
116 
117     /**
118      * Called after BindingTarget is finalized.
119      * <p>
120      * We traverse all bindings and ask SetterStore to figure out if any can be combined.
121      * When N bindings are combined, they are demoted from being a binding expression and a new
122      * ArgList expression is added as the new binding expression that depends on others.
123      */
resolveMultiSetters()124     public void resolveMultiSetters() {
125         L.d("resolving multi setters for %s", getId());
126         final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
127         final String[] attributes = new String[mBindings.size()];
128         final ModelClass[] types = new ModelClass[mBindings.size()];
129         for (int i = 0; i < mBindings.size(); i ++) {
130             Binding binding = mBindings.get(i);
131             try {
132                 Scope.enter(binding);
133                 attributes[i] = binding.getName();
134                 types[i] = binding.getExpr().getResolvedType();
135             } finally {
136                 Scope.exit();
137             }
138         }
139         final List<SetterStore.MultiAttributeSetter> multiAttributeSetterCalls = setterStore
140                 .getMultiAttributeSetterCalls(attributes, getResolvedType(), types);
141         if (multiAttributeSetterCalls.isEmpty()) {
142             return;
143         }
144         final Map<String, Binding> lookup = new HashMap<String, Binding>();
145         for (Binding binding : mBindings) {
146             String name = binding.getName();
147             if (name.startsWith("android:")) {
148                 lookup.put(name, binding);
149             } else {
150                 int ind = name.indexOf(":");
151                 if (ind == -1) {
152                     lookup.put(name, binding);
153                 } else {
154                     lookup.put(name.substring(ind + 1), binding);
155                 }
156             }
157         }
158         List<MergedBinding> mergeBindings = new ArrayList<MergedBinding>();
159         for (final SetterStore.MultiAttributeSetter setter : multiAttributeSetterCalls) {
160             L.d("resolved %s", setter);
161             final List<Binding> mergedBindings = new ArrayList<>();
162             for (String attribute : setter.attributes) {
163                 Binding binding = lookup.get(attribute);
164                 Preconditions.checkNotNull(binding, "cannot find binding for %s", attribute);
165                 mergedBindings.add(binding);
166             }
167 
168             for (Binding binding : mergedBindings) {
169                 binding.getExpr().setBindingExpression(false);
170                 mBindings.remove(binding);
171             }
172             MergedBinding mergedBinding = new MergedBinding(getModel(), setter, this,
173                     mergedBindings);
174             mergeBindings.add(mergedBinding);
175         }
176         for (MergedBinding binding : mergeBindings) {
177             mBindings.add(binding);
178         }
179     }
180 }
181