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
19bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mountimport android.databinding.tool.expr.CallbackArgExpr;
20bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mountimport android.databinding.tool.expr.CallbackExprModel;
21d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.expr.Expr;
22d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.expr.ExprModel;
23d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.expr.FieldAccessExpr;
24bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mountimport android.databinding.tool.expr.IdentifierExpr;
25d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.processing.ErrorMessages;
26d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.processing.Scope;
27d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.processing.scopes.LocationScopeProvider;
28d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.reflection.ModelAnalyzer;
29d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.reflection.ModelClass;
30bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mountimport android.databinding.tool.solver.ExecutionPath;
31d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.Location;
32d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.SetterStore;
33d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.SetterStore.BindingGetterCall;
34d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.store.SetterStore.BindingSetterCall;
35d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport android.databinding.tool.util.L;
36d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
37d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport java.util.ArrayList;
38d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountimport java.util.List;
39d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
40d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mountpublic class InverseBinding implements LocationScopeProvider {
41d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
42d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    private final String mName;
43d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    private final Expr mExpr;
44d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    private final BindingTarget mTarget;
45d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    private BindingGetterCall mGetterCall;
46d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    private final ArrayList<FieldAccessExpr> mChainedExpressions = new ArrayList<FieldAccessExpr>();
47bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    private final CallbackExprModel mCallbackExprModel;
48bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    private final Expr mInverseExpr;
49bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    private final CallbackArgExpr mVariableExpr;
50bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    private final ExecutionPath mExecutionPath;
51bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
52bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public InverseBinding(BindingTarget target, String name, Expr expr, String bindingClassName) {
53bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mTarget = target;
54bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mName = name;
55bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mCallbackExprModel = new CallbackExprModel(expr.getModel());
56bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mExpr = expr.cloneToModel(mCallbackExprModel);
57bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        setGetterCall(mExpr);
58bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mVariableExpr = mCallbackExprModel.callbackArg("callbackArg_0");
59bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance();
60bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        ModelClass type = modelAnalyzer.findClass(getGetterCall().getGetterType(), null);
61bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mVariableExpr.setClassFromCallback(type);
62bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mVariableExpr.setUserDefinedType(getGetterCall().getGetterType());
63bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mInverseExpr =
64bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount                mExpr.generateInverse(mCallbackExprModel, mVariableExpr, bindingClassName);
65bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mExecutionPath = ExecutionPath.createRoot();
66bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mInverseExpr.toExecutionPath(mExecutionPath);
67bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mCallbackExprModel.seal();
68bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
69d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
70bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public InverseBinding(BindingTarget target, String name, BindingGetterCall getterCall) {
71d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        mTarget = target;
72d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        mName = name;
73bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mExpr = null;
74bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mCallbackExprModel = null;
75bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mInverseExpr = null;
76bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mVariableExpr = null;
77bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        mExecutionPath = null;
78bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        setGetterCall(getterCall);
79d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
80d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
81d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    @Override
82d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public List<Location> provideScopeLocation() {
83d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (mExpr != null) {
84d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            return mExpr.getLocations();
85d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        } else {
86d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            return mChainedExpressions.get(0).getLocations();
87d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
88d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
89d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
90bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    private void setGetterCall(BindingGetterCall getterCall) {
91d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        mGetterCall = getterCall;
92d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
93d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
94d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public void addChainedExpression(FieldAccessExpr expr) {
95d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        mChainedExpressions.add(expr);
96d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
97d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
98d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public boolean isOnBinder() {
99d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return mTarget.getResolvedType().isViewDataBinding();
100d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
101d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
102bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    private void setGetterCall(Expr expr) {
103bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        try {
104bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            Scope.enter(mTarget);
105bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            Scope.enter(this);
106bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            ModelClass viewType = mTarget.getResolvedType();
107bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            final SetterStore setterStore = SetterStore.get(ModelAnalyzer.getInstance());
108bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            final ModelClass resolvedType = expr == null ? null : expr.getResolvedType();
109bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            mGetterCall = setterStore.getGetterCall(mName, viewType, resolvedType,
110bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount                    expr.getModel().getImports());
111bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            if (mGetterCall == null) {
112bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount                L.e(ErrorMessages.CANNOT_FIND_GETTER_CALL, mName,
113bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount                        expr == null ? "Unknown" : mExpr.getResolvedType(),
114bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount                        mTarget.getResolvedType());
115d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            }
116bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        } finally {
117bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            Scope.exit();
118bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount            Scope.exit();
119d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
120d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
121d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
122bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public SetterStore.BindingGetterCall getGetterCall() {
123bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return mGetterCall;
124d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
125d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
126d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public BindingTarget getTarget() {
127d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return mTarget;
128d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
129d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
130bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public Expr getExpr() {
131bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return mExpr;
132bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
133bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
134bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public Expr getInverseExpr() {
135bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return mInverseExpr;
136bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
137bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
138bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public IdentifierExpr getVariableExpr() {
139bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return mVariableExpr;
140bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
141bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
142bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public ExecutionPath getExecutionPath() {
143bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return mExecutionPath;
144bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
145bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
146bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public CallbackExprModel getCallbackExprModel() {
147bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return mCallbackExprModel;
148bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    }
149bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount
150bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount    public List<FieldAccessExpr> getChainedExpressions() {
151bb4a033fcd5cd20e5be46ef8ead442dc7db2454dGeorge Mount        return mChainedExpressions;
152d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
153d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
154d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public String getBindingAdapterInstanceClass() {
155d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return getGetterCall().getBindingAdapterInstanceClass();
156d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
157d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
158d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    /**
159d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     * The min api level in which this binding should be executed.
160d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     * <p>
161d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     * This should be the minimum value among the dependencies of this binding.
162d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount     */
163d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public int getMinApi() {
164d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        final BindingGetterCall getterCall = getGetterCall();
165d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return Math.max(getterCall.getMinApi(), getterCall.getEvent().getMinApi());
166d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
167d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
168d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public BindingSetterCall getEventSetter() {
169d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        final BindingGetterCall getterCall = getGetterCall();
170d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return getterCall.getEvent();
171d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
172d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
173d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public String getName() {
174d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return mName;
175d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
176d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
177d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public String getEventAttribute() {
178d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return getGetterCall().getEventAttribute();
179d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
180d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount
181d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    public ExprModel getModel() {
182d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        if (mExpr != null) {
183d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount            return mExpr.getModel();
184d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        }
185d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount        return mChainedExpressions.get(0).getModel();
186d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount    }
187d3f2b9229472c9dae9bf4ae8b3e2d653b5653b01George Mount}
188