Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30bc4d25 authored by Yigit Boyar's avatar Yigit Boyar
Browse files

Fix how we handle non-bindable fields in Observable objects

Change-Id: Ia33200a2ade3bd3ed8d3a66e1602a04111f4387a
parent b389318b
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.databinding.testapp.com.android.databinding.testapp.vo;

import com.android.databinding.testapp.BaseDataBinderTest;
import com.android.databinding.testapp.R;
import com.android.databinding.testapp.generated.ObservableWithNotBindableFieldBinder;
import com.android.databinding.testapp.vo.ObservableWithNotBindableFieldObject;

import android.test.UiThreadTest;

public class ObservableWithNotBindableFieldObjectTest extends BaseDataBinderTest<ObservableWithNotBindableFieldBinder> {


    public ObservableWithNotBindableFieldObjectTest() {
        super(ObservableWithNotBindableFieldBinder.class, R.layout.observable_with_not_bindable_field);
    }

    @UiThreadTest
    public void testSimple() {
        ObservableWithNotBindableFieldObject obj = new ObservableWithNotBindableFieldObject();
        mBinder.setObj(obj);
        mBinder.rebindDirty();
        assertEquals("", mBinder.getTextView().getText().toString());
        obj.update("100");
        mBinder.rebindDirty();
        assertEquals("100", mBinder.getTextView().getText().toString());
    }
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.databinding.testapp.vo;

import com.android.databinding.library.BaseObservable;

public class ObservableWithNotBindableFieldObject extends BaseObservable {
    private String data;
    public void update(String data) {
        this.data = data;
        notifyChange();
    }

    public String getData() {
        return data;
    }
}
+23 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright (C) 2015 The Android Open Source Project
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <variable name="obj" type="com.android.databinding.testapp.vo.ObservableWithNotBindableFieldObject"/>
    <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:id="@+id/text_view"
            android:text="@{obj.data}"/>
</LinearLayout>
 No newline at end of file
+51 −28
Original line number Diff line number Diff line
@@ -54,7 +54,8 @@ public class ClassAnalyzer {
            OBSERVABLE_CLASS_NAME, "com.android.databinding.MockObservable",
            BINDABLE_ANNOTATION_NAME, "com.android.databinding.MockBindable",
            OBSERVABLE_LIST_CLASS_NAME, "com.android.databinding.MockObservableLsit",
            OBSERVABLE_MAP_CLASS_NAME, "com.android.databinding.MockObservableMap"
            OBSERVABLE_MAP_CLASS_NAME, "com.android.databinding.MockObservableMap",
            I_VIEW_DATA_BINDER, "com.android.databinding.MockIViewDataBinder"
    );

    private static ClassAnalyzer sClassAnalyzer;
@@ -172,34 +173,25 @@ public class ClassAnalyzer {
    public Callable findMethodOrField(Class klass, String name) {

        for (String methodName :
                new String[]{"get" + StringUtils.capitalize(name), name}) {
                new String[]{"get" + StringUtils.capitalize(name),
                        "is" + StringUtils.capitalize(name), name}) {
            try {
                Method method = klass.getMethod(methodName);
                Field backingField = findField(klass, name);
                Field backingField = findField(klass, name, true);
                if (Modifier.isPublic(method.getModifiers())) {
                    return new Callable(Callable.Type.METHOD, methodName, method.getReturnType(),
                            true, isBindable(method) || (backingField != null && isBindable(backingField)) );
                    final Callable result = new Callable(Callable.Type.METHOD, methodName,
                            method.getReturnType(),
                            true, isBindable(method) || (backingField != null && isBindable(
                            backingField)));
                    L.d("backing field for %s is %s", result, backingField);
                    return result;
                }
            } catch (Throwable t) {

            }
        }
        for (String methodName :
                new String[]{"is" + StringUtils.capitalize(name), name}) {
        try {
                Method method = klass.getMethod(methodName);
                Field backingField = findField(klass, name);

                if (Modifier.isPublic(method.getModifiers())) {
                    return new Callable(Callable.Type.METHOD, methodName, method.getReturnType(),
                            true, isBindable(method) || (backingField != null && isBindable(backingField)) );
                }
            } catch (Throwable t) {

            }
        }
        try {
            Field field = klass.getField(name);
            Field field = findField(klass, name, false);
            if (Modifier.isPublic(field.getModifiers())) {
                return new Callable(Callable.Type.FIELD, name, field.getType(),
                        !Modifier.isFinal(field.getModifiers())
@@ -212,29 +204,49 @@ public class ClassAnalyzer {
                "cannot find " + name + " in " + klass.getCanonicalName());
    }

    private Field findField(Class klass, String name) {
    private Field findField(Class klass, String name, boolean allowNonPublic) {
        try {
            return klass.getDeclaredField(name);
        } catch (Throwable t){}
            return getField(klass, name, allowNonPublic);
        } catch (NoSuchFieldException e) {

        }
        String capitalizedName = StringUtils.capitalize(name);

        try {
            return klass.getField("m" + capitalizedName);
            return getField(klass, "m" + capitalizedName, allowNonPublic);
        } catch (Throwable t){}
        try {
            return klass.getField("_" + name);
            return getField(klass, "_" + name, allowNonPublic);
        } catch (Throwable t){}
        try {
            return klass.getField("_" + capitalizedName);
            return getField(klass, "_" + capitalizedName, allowNonPublic);
        } catch (Throwable t){}
        try {
            return klass.getField("m_" + name);
            return getField(klass, "m_" + name, allowNonPublic);
        } catch (Throwable t){}
        try {
            return klass.getField("m_" + capitalizedName);
            return getField(klass, "m_" + capitalizedName, allowNonPublic);
        } catch (Throwable t){}
        return null;
    }

    private Field getField(Class klass, String exactName, boolean allowNonPublic)
            throws NoSuchFieldException {
        try {
            return klass.getField(exactName);
        } catch (NoSuchFieldException e) {
            if (allowNonPublic) {
                return klass.getDeclaredField(exactName);
            } else {
                throw e;
            }
        }
    }

    private Field findField(Class klass, String name) {
        return findField(klass, name, false);
    }

    public Class findCommonParentOf(Class klass1, Class klass2) {
        Class curr = klass1;
        while (curr != null && !curr.isAssignableFrom(klass2)) {
@@ -392,5 +404,16 @@ public class ClassAnalyzer {
        public String getTypeCodeName() {
            return ClassAnalyzer.toCodeName(resolvedType);
        }

        @Override
        public String toString() {
            return "Callable{" +
                    "type=" + type +
                    ", name='" + name + '\'' +
                    ", resolvedType=" + resolvedType +
                    ", isDynamic=" + isDynamic +
                    ", canBeInvalidated=" + canBeInvalidated +
                    '}';
        }
    }
}
+12 −9
Original line number Diff line number Diff line
@@ -234,8 +234,10 @@ public class ExprModel {
                    continue;// already has some id, means observable
                }
                // only fields earn an id
                if (parent instanceof FieldAccessExpr && parent.isDynamic() &&
                        !((FieldAccessExpr) parent).getName().isEmpty()) {
                if (parent instanceof FieldAccessExpr) {
                    FieldAccessExpr fae = (FieldAccessExpr) parent;
                    L.d("checking field access expr %s. getter: %s", fae,fae.getGetter());
                    if (fae.isDynamic() && fae.getGetter().canBeInvalidated) {
                        flagMapping.add(parent.getUniqueKey());
                        parent.setId(counter++);
                        notifiableExpressions.add(parent);
@@ -246,6 +248,7 @@ public class ExprModel {
                    }
                }
            }
        }

        // non-dynamic binding expressions receive some ids so that they can be invalidated
        for (Expr expr : mBindingExpressions) {
Loading