diff options
author | George Mount <mount@google.com> | 2015-09-17 07:42:41 -0700 |
---|---|---|
committer | George Mount <mount@google.com> | 2016-02-23 15:05:20 -0800 |
commit | b7eeedbfadec03792551014e9dfa2bd384fc21a3 (patch) | |
tree | 27a2c93238a1b1f9e83a1b36e47889075aa43cf4 | |
parent | b522c7650bf7d9ec566845bc9eb37e761eea853d (diff) | |
download | data-binding-b7eeedbfadec03792551014e9dfa2bd384fc21a3.tar.gz |
Two-way binding tests
Bug 1474349
Bug 22460238
Tests for two-way data binding can't be checked in until the
SDK becomes public. Also updates the sample application because
it has the same restrictions.
Change-Id: I7e2b2f84943844401d2b8edbac4e60ea9f5704a6
18 files changed, 1101 insertions, 42 deletions
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java index f38dcc4f..3525b3a8 100644 --- a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java +++ b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java @@ -16,13 +16,6 @@ package android.databinding.compilationTest; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.PrefixFileFilter; -import org.apache.commons.io.filefilter.SuffixFileFilter; -import org.apache.commons.lang3.StringUtils; -import org.junit.Test; - import android.databinding.tool.processing.ErrorMessages; import android.databinding.tool.processing.ScopedErrorReport; import android.databinding.tool.processing.ScopedException; @@ -30,6 +23,12 @@ import android.databinding.tool.store.Location; import com.google.common.base.Joiner; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.PrefixFileFilter; +import org.apache.commons.io.filefilter.SuffixFileFilter; +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; + import java.io.File; import java.io.IOException; import java.net.URISyntaxException; @@ -37,7 +36,6 @@ import java.util.Collection; import java.util.List; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -327,4 +325,25 @@ public class SimpleCompilationTest extends BaseCompilationTest { assertEquals("Merge shouldn't support includes as root. Error message was '" + result.error, ErrorMessages.INCLUDE_INSIDE_MERGE, ex.getBareMessage()); } + + @Test + public void testAssignTwoWayEvent() throws Throwable { + prepareProject(); + copyResourceTo("/layout/layout_with_two_way_event_attribute.xml", + "/app/src/main/res/layout/layout_with_two_way_event_attribute.xml"); + CompilationResult result = runGradle("assembleDebug"); + assertNotEquals(0, result.resultCode); + List<ScopedException> errors = ScopedException.extractErrors(result.error); + assertEquals(result.error, 1, errors.size()); + final ScopedException ex = errors.get(0); + final ScopedErrorReport report = ex.getScopedErrorReport(); + final File errorFile = new File(report.getFilePath()); + assertTrue(errorFile.exists()); + assertEquals(new File(testFolder, + "/app/src/main/res/layout/layout_with_two_way_event_attribute.xml") + .getCanonicalFile(), + errorFile.getCanonicalFile()); + assertEquals("The attribute android:textAttrChanged is a two-way binding event attribute " + + "and cannot be assigned.", ex.getBareMessage()); + } } diff --git a/compilationTests/src/test/resources/layout/layout_with_two_way_event_attribute.xml b/compilationTests/src/test/resources/layout/layout_with_two_way_event_attribute.xml new file mode 100644 index 00000000..16536e34 --- /dev/null +++ b/compilationTests/src/test/resources/layout/layout_with_two_way_event_attribute.xml @@ -0,0 +1,35 @@ +<?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. + --> + +<layout xmlns:android="http://schemas.android.com/apk/res/android" +> + <data> + <variable name="myVariable" type="String"/> + <variable name="myEventListener" type="android.databinding.InverseBindingListener"/> + </data> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <!-- undefined variable --> + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/textView" + android:text="@{myVariable}" + android:textAttrChanged="@{myEventListener}"/> + </LinearLayout> +</layout>
\ No newline at end of file diff --git a/integration-tests/TestApp/app/src/androidTestApi14/java/android/databinding/testapp/RootTag.java b/integration-tests/TestApp/app/src/androidTestApi14/java/android/databinding/testapp/RootTag.java index 132beb6e..9adc8f30 100644 --- a/integration-tests/TestApp/app/src/androidTestApi14/java/android/databinding/testapp/RootTag.java +++ b/integration-tests/TestApp/app/src/androidTestApi14/java/android/databinding/testapp/RootTag.java @@ -15,21 +15,17 @@ */ package android.databinding.testapp; -import android.databinding.testapp.BaseDataBinderTest; import android.databinding.testapp.databinding.RootTagBinding; +import android.test.UiThreadTest; public class RootTag extends BaseDataBinderTest<RootTagBinding> { public RootTag() { super(RootTagBinding.class); } - @Override - protected void setUp() throws Exception { - super.setUp(); - initBinder(); - } - + @UiThreadTest public void testRootTagSet() throws Throwable { + initBinder(); mBinder.executePendingBindings(); assertEquals("foo", mBinder.textView1.getTag()); assertEquals("hello world", mBinder.textView1.getText().toString()); diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java index 136b7ccb..a4cda6a2 100644 --- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java +++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/BracketTest.java @@ -94,7 +94,7 @@ public class BracketTest extends BaseDataBinderTest<BracketTestBinding> { @UiThreadTest public void testBracketObj() { mBinder.executePendingBindings(); - assertEquals("Hello World", mBinder.indexObj.getText().toString()); + assertEquals("Hello World", mBinder.indexObjView.getText().toString()); assertEquals("Hello", mBinder.sparseArrayTextObj.getText().toString()); } diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java index 8f63bcc8..5d00b669 100644 --- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java +++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/LeakTest.java @@ -19,6 +19,7 @@ import android.util.Log; import android.widget.FrameLayout; import java.lang.ref.WeakReference; +import java.util.ArrayList; public class LeakTest extends ActivityInstrumentationTestCase2<TestActivity> { WeakReference<LeakTestBinding> mWeakReference = new WeakReference<LeakTestBinding>(null); @@ -63,8 +64,9 @@ public class LeakTest extends ActivityInstrumentationTestCase2<TestActivity> { } }); WeakReference<Object> canary = new WeakReference<Object>(new Object()); + ArrayList<WeakReference<byte[]>> leak = new ArrayList<>(); while (canary.get() != null) { - byte[] b = new byte[1024 * 1024]; + leak.add(new WeakReference<byte[]>(new byte[100])); System.gc(); } assertNull(mWeakReference.get()); diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java index c6bc6715..83dfe728 100644 --- a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java +++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TextViewBindingAdapterTest.java @@ -31,6 +31,7 @@ import android.text.method.DialerKeyListener; import android.text.method.DigitsKeyListener; import android.text.method.KeyListener; import android.text.method.TextKeyListener; +import android.widget.EditText; import android.widget.TextView; public class TextViewBindingAdapterTest @@ -315,4 +316,14 @@ public class TextViewBindingAdapterTest android.R.color.holo_blue_bright); assertEquals(expectedColor, textView.getCurrentTextColor()); } + + @UiThreadTest + public void testTwoWayText() throws Throwable { + EditText view = mBinder.twoWayText; + mBindingObject.setText("Hello"); + mBinder.executePendingBindings(); + assertEquals("Hello", view.getText().toString()); + view.setText("World"); + assertEquals("World", mBindingObject.getText()); + } } diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TwoWayBindingAdapterTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TwoWayBindingAdapterTest.java new file mode 100644 index 00000000..7506f2b5 --- /dev/null +++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/TwoWayBindingAdapterTest.java @@ -0,0 +1,718 @@ +/* + * 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 android.databinding.testapp; + +import android.app.Instrumentation; +import android.content.Context; +import android.databinding.testapp.databinding.TwoWayBinding; +import android.databinding.testapp.vo.TwoWayBindingObject; +import android.os.SystemClock; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.style.BackgroundColorSpan; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TabHost.TabSpec; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TwoWayBindingAdapterTest extends BaseDataBinderTest<TwoWayBinding> { + + TwoWayBindingObject mBindingObject; + + public TwoWayBindingAdapterTest() { + super(TwoWayBinding.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + initBinder(new Runnable() { + @Override + public void run() { + Context context = getBinder().getRoot().getContext(); + mBindingObject = new TwoWayBindingObject(context); + getBinder().setObj(mBindingObject); + getBinder().executePendingBindings(); + } + }); + } + + public void testListViewSelectedItemPosition() throws Throwable { + makeVisible(mBinder.listView); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(0, mBindingObject.selectedItemPosition.get()); + assertEquals(0, mBinder.listView.getSelectedItemPosition()); + mBinder.listView.setSelection(1); + } + }); + long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.selectedItemPosition.get() == 0 && + SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1, mBinder.listView.getSelectedItemPosition()); + assertEquals(1, mBindingObject.selectedItemPosition.get()); + } + }); + } + + private void clickView(final View view, float offsetX) throws Throwable { + final int[] xy = new int[2]; + final int[] viewSize = new int[2]; + do { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + view.getLocationOnScreen(xy); + viewSize[0] = view.getWidth(); + viewSize[1] = view.getHeight(); + } + }); + } while (xy[0] < 0 || xy[1] < 0); + + final float x = xy[0] + offsetX; + final float y = xy[1] + (viewSize[1] / 2f); + + Instrumentation inst = getInstrumentation(); + + long downTime = SystemClock.uptimeMillis(); + long eventTime = SystemClock.uptimeMillis(); + + MotionEvent event = MotionEvent.obtain(downTime, eventTime, + MotionEvent.ACTION_DOWN, x, y, 0); + inst.sendPointerSync(event); + inst.waitForIdleSync(); + + eventTime = SystemClock.uptimeMillis(); + final int touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop(); + event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, + x + (touchSlop / 2.0f), y + (touchSlop / 2.0f), 0); + inst.sendPointerSync(event); + inst.waitForIdleSync(); + + eventTime = SystemClock.uptimeMillis(); + event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); + inst.sendPointerSync(event); + inst.waitForIdleSync(); + } + + private void clickChild(View view, float offsetX) throws Throwable { + View childView = view; + while (childView != null) { + childView.callOnClick(); + if (childView instanceof ViewGroup) { + final ViewGroup viewGroup = (ViewGroup) childView; + if (viewGroup.getChildCount() > 0) { + childView = viewGroup.getChildAt(0); + } else { + childView = null; + } + } else { + clickView(childView, offsetX); + childView = null; + } + } + } + + public void testCalendarViewDate() throws Throwable { + makeVisible(mBinder.calendarView); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertNotSame(0, mBindingObject.date.get()); + assertEquals(mBindingObject.date.get(), mBinder.calendarView.getDate()); + } + }); + final long[] date = new long[2]; + float offsetX = 0; + long timeout = SystemClock.uptimeMillis() + 1500; + do { + // Just randomly poke at the CalendarView to set the date + clickChild(mBinder.calendarView, offsetX); + offsetX += 48; + runTestOnUiThread(new Runnable() { + @Override + public void run() { + date[0] = mBinder.calendarView.getDate(); + if (date[1] == 0) { + date[1] = date[0]; + } + } + }); + } while (date[0] == date[1] && SystemClock.uptimeMillis() < timeout); + + timeout = SystemClock.uptimeMillis() + 100; + while (mBindingObject.date.get() == 0 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + assertEquals(date[0], mBindingObject.date.get()); + } + + public void testCheckBoxChecked() throws Throwable { + makeVisible(mBinder.checkBox); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertFalse(mBindingObject.checked.get()); + assertFalse(mBinder.checkBox.isChecked()); + mBinder.checkBox.setChecked(true); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (!mBindingObject.checked.get() && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertTrue(mBinder.checkBox.isChecked()); + assertTrue(mBindingObject.checked.get()); + } + }); + } + + private boolean focusOn(final View view) throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + view.requestFocus(); + } + }); + long timeout = SystemClock.uptimeMillis() + 500; + final boolean[] focused = new boolean[1]; + while (SystemClock.uptimeMillis() < timeout) { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + focused[0] = view.isFocused(); + } + }); + if (focused[0]) { + return true; + } + } + return false; + } + + public void testNumberPickerNumber() throws Throwable { + makeVisible(mBinder.textView, mBinder.numberPicker); + assertTrue(focusOn(mBinder.textView)); + final EditText[] pickerText = new EditText[1]; + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1, mBindingObject.number.get()); + assertEquals(1, mBinder.numberPicker.getValue()); + for (int i = 0; i < mBinder.numberPicker.getChildCount(); i++) { + View view = mBinder.numberPicker.getChildAt(i); + if (view instanceof EditText) { + pickerText[0] = (EditText) view; + break; + } + } + } + }); + assertNotNull(pickerText[0]); + assertTrue(focusOn(pickerText[0])); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + pickerText[0].setText("10"); + } + }); + assertTrue(focusOn(mBinder.textView)); + + final long timeout = SystemClock.uptimeMillis() + 10; + while (mBindingObject.number.get() == 1 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(10, mBinder.numberPicker.getValue()); + assertEquals(10, mBindingObject.number.get()); + } + }); + } + + public void testRatingBarRating() throws Throwable { + makeVisible(mBinder.ratingBar); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1f, mBindingObject.rating.get()); + assertEquals(1f, mBinder.ratingBar.getRating()); + mBinder.ratingBar.setRating(2.5f); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.rating.get() == 1f && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(2.5f, mBinder.ratingBar.getRating()); + assertEquals(2.5f, mBindingObject.rating.get()); + } + }); + } + + public void testSeekBarProgress() throws Throwable { + makeVisible(mBinder.seekBar); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1, mBindingObject.progress.get()); + assertEquals(1, mBinder.seekBar.getProgress()); + mBinder.seekBar.setProgress(30); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.progress.get() == 1 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(30, mBinder.seekBar.getProgress()); + assertEquals(30, mBindingObject.progress.get()); + } + }); + } + + public void testTabHostCurrentTab() throws Throwable { + makeVisible(mBinder.tabhost); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + mBinder.tabhost.setup(); + TabSpec tab1 = mBinder.tabhost.newTabSpec("Tab1"); + TabSpec tab2 = mBinder.tabhost.newTabSpec("Tab2"); + + tab1.setIndicator("tab1"); + tab1.setContent(R.id.foo); + tab2.setIndicator("tab2"); + tab2.setContent(R.id.bar); + mBinder.tabhost.addTab(tab1); + mBinder.tabhost.addTab(tab2); + mBinder.tabhost.setCurrentTab(1); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.currentTab.get() == 0 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1, mBinder.tabhost.getCurrentTab()); + assertEquals(1, mBindingObject.currentTab.get()); + } + }); + } + + public void testTextViewText() throws Throwable { + makeVisible(mBinder.textView); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(null, mBindingObject.text.get()); + assertEquals("", mBinder.textView.getText().toString()); + mBinder.textView.setText("Hello World"); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.text.get().isEmpty() && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals("Hello World", mBinder.textView.getText().toString()); + assertEquals("Hello World", mBindingObject.text.get()); + } + }); + } + + public void testDatePicker() throws Throwable { + makeVisible(mBinder.datePicker); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1972, mBindingObject.year.get()); + assertEquals(9, mBindingObject.month.get()); + assertEquals(21, mBindingObject.day.get()); + assertEquals(1972, mBinder.datePicker.getYear()); + assertEquals(9, mBinder.datePicker.getMonth()); + assertEquals(21, mBinder.datePicker.getDayOfMonth()); + mBinder.datePicker.updateDate(2003, 4, 17); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.year.get() == 1972 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(2003, mBindingObject.year.get()); + assertEquals(4, mBindingObject.month.get()); + assertEquals(17, mBindingObject.day.get()); + } + }); + } + + public void testExpressions1() throws Throwable { + makeVisible(mBinder.expressions1); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1972, mBindingObject.year.get()); + assertEquals(9, mBindingObject.month.get()); + assertEquals(21, mBindingObject.day.get()); + assertEquals(1972000, mBinder.expressions1.getYear()); + assertEquals(2, mBinder.expressions1.getMonth()); + assertEquals(22, mBinder.expressions1.getDayOfMonth()); + mBinder.expressions1.updateDate(2003000, 3, 18); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.year.get() == 1972 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(2003, mBindingObject.year.get()); + assertEquals(8, mBindingObject.month.get()); + assertEquals(17, mBindingObject.day.get()); + } + }); + } + + public void testExpressions2() throws Throwable { + makeVisible(mBinder.expressions2); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1972, mBindingObject.year.get()); + assertEquals(9, mBindingObject.month.get()); + assertEquals(21, mBindingObject.day.get()); + assertEquals(1, mBinder.expressions2.getYear()); + assertEquals(9, mBinder.expressions2.getMonth()); + assertEquals(21, mBinder.expressions2.getDayOfMonth()); + mBinder.expressions2.updateDate(2, 4, 17); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.year.get() == 1972 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(2000, mBindingObject.year.get()); + assertEquals(4, mBindingObject.month.get()); + assertEquals(17, mBindingObject.day.get()); + } + }); + } + + public void testExpressions3() throws Throwable { + makeVisible(mBinder.expressions3); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals((Integer)1, mBindingObject.list.get(1)); + assertEquals((Integer)2, mBindingObject.map.get("two")); + assertEquals(2, mBindingObject.array.get()[1]); + assertEquals(1, mBinder.expressions3.getYear()); + assertEquals(2, mBinder.expressions3.getMonth()); + assertEquals(2, mBinder.expressions3.getDayOfMonth()); + mBinder.expressions3.updateDate(2003, 4, 17); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.year.get() == 1972 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals((Integer)2003, mBindingObject.list.get(1)); + assertEquals((Integer)4, mBindingObject.map.get("two")); + assertEquals(17, mBindingObject.array.get()[1]); + } + }); + } + + public void testExpressions4() throws Throwable { + makeVisible(mBinder.expressions4); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(1972, mBindingObject.year.get()); + assertEquals(9, mBindingObject.month.get()); + assertEquals(21, mBindingObject.day.get()); + assertEquals(50, mBinder.expressions4.getYear()); + assertEquals(5, mBinder.expressions4.getMonth()); + assertEquals(21, mBinder.expressions4.getDayOfMonth()); + mBinder.expressions4.updateDate(49, 4, 17); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.year.get() == 1972 && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(2040, mBindingObject.year.get()); + assertEquals(6, mBindingObject.month.get()); + assertEquals(17, mBindingObject.day.get()); + } + }); + } + + public void testChaining() throws Throwable { + makeVisible(mBinder.checkBox, mBinder.checkBox2); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertTrue(mBinder.checkBox2.isChecked()); + mBindingObject.checked.set(true); + mBinder.executePendingBindings(); + assertFalse(mBinder.checkBox2.isChecked()); + } + }); + } + + public void testTwoWayChaining() throws Throwable { + makeVisible(mBinder.checkBox3, mBinder.checkBox4); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertFalse(mBinder.checkBox3.isChecked()); + assertTrue(mBinder.checkBox4.isChecked()); + mBinder.checkBox3.setChecked(true); + mBinder.executePendingBindings(); + assertTrue(mBinder.checkBox3.isChecked()); + assertFalse(mBinder.checkBox4.isChecked()); + } + }); + } + + public void testIncludedTwoWay1() throws Throwable { + makeVisible(mBinder.included.editText1, mBinder.textView); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(null, mBindingObject.text.get()); + assertEquals("", mBinder.textView.getText().toString()); + assertEquals("", mBinder.included.editText1.getText().toString()); + mBinder.included.editText1.setText("Hello World"); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.text.get().isEmpty() && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals("Hello World", mBinder.included.editText1.getText().toString()); + assertEquals("Hello World", mBinder.textView.getText().toString()); + assertEquals("Hello World", mBindingObject.text.get()); + } + }); + } + + public void testIncludedTwoWay2() throws Throwable { + makeVisible(mBinder.included.editText2, mBinder.textView); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(null, mBindingObject.text.get()); + assertEquals("", mBinder.textView.getText().toString()); + assertEquals("", mBinder.included.editText2.getText().toString()); + mBinder.included.editText2.setText("Hello World"); + } + }); + + final long timeout = SystemClock.uptimeMillis() + 500; + while (mBindingObject.text.get().isEmpty() && SystemClock.uptimeMillis() < timeout) { + Thread.sleep(1); + } + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals("Hello World", mBinder.included.editText2.getText().toString()); + assertEquals("Hello World", mBinder.textView.getText().toString()); + assertEquals("Hello World", mBindingObject.text.get()); + } + }); + } + + public void testNoEditableLoop() throws Throwable { + makeVisible(mBinder.editText1, mBinder.editText2); + + final SpannableString text = new SpannableString("Hello World Also"); + BackgroundColorSpan highlight = new BackgroundColorSpan(0xFFFFFF80); + text.setSpan(highlight, 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + mBindingObject.textLatch = new CountDownLatch(2); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals("", mBinder.editText1.getText().toString()); + assertEquals(0, mBindingObject.text1Changes); + assertEquals(0, mBindingObject.text2Changes); + + // Change the text of one of the controls + mBinder.editText1.setText("Hello World"); + } + }); + + assertTrue(mBindingObject.textLatch.await(500, TimeUnit.MILLISECONDS)); + mBindingObject.textLatch = new CountDownLatch(2); + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertNotNull(mBindingObject.editText.get()); + assertEquals("Hello World", mBindingObject.editText.get().toString()); + // They should both be set + assertEquals(1, mBindingObject.text1Changes); + assertEquals(1, mBindingObject.text2Changes); + + // Edit the span, but the text remains the same. + mBinder.editText2.setText(text); + } + }); + + assertTrue(mBindingObject.textLatch.await(500, TimeUnit.MILLISECONDS)); + mBindingObject.textLatch = new CountDownLatch(1); + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + // The one control should notify a change, but not the other. + assertEquals(2, mBindingObject.text1Changes); + assertEquals(2, mBindingObject.text2Changes); + + // No more changes should occur + mBinder.executePendingBindings(); + } + }); + + assertFalse(mBindingObject.textLatch.await(200, TimeUnit.MILLISECONDS)); + mBindingObject.textLatch = new CountDownLatch(2); + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + // Nothing changed: + assertEquals(2, mBindingObject.text1Changes); + assertEquals(2, mBindingObject.text2Changes); + + // Now try changing the value to the same thing. Because the + // value is Spannable, it will set it to the EditText + // and then get back a String in the onTextChanged. + mBindingObject.editText.set(text); + } + }); + + assertTrue(mBindingObject.textLatch.await(500, TimeUnit.MILLISECONDS)); + + runTestOnUiThread(new Runnable() { + @Override + public void run() { + assertEquals(3, mBindingObject.text1Changes); + assertEquals(3, mBindingObject.text2Changes); + assertEquals("Hello World Also", mBindingObject.editText.get()); + } + }); + } + + private void makeVisible(final View... views) throws Throwable { + runTestOnUiThread(new Runnable() { + @Override + public void run() { + mBinder.calendarView.setVisibility(View.GONE); + mBinder.listView.setVisibility(View.GONE); + mBinder.checkBox.setVisibility(View.GONE); + mBinder.numberPicker.setVisibility(View.GONE); + mBinder.ratingBar.setVisibility(View.GONE); + mBinder.seekBar.setVisibility(View.GONE); + mBinder.tabhost.setVisibility(View.GONE); + mBinder.textView.setVisibility(View.GONE); + mBinder.timePicker.setVisibility(View.GONE); + mBinder.datePicker.setVisibility(View.GONE); + mBinder.expressions1.setVisibility(View.GONE); + mBinder.expressions2.setVisibility(View.GONE); + mBinder.expressions3.setVisibility(View.GONE); + mBinder.expressions4.setVisibility(View.GONE); + mBinder.checkBox2.setVisibility(View.GONE); + mBinder.checkBox3.setVisibility(View.GONE); + mBinder.checkBox4.setVisibility(View.GONE); + mBinder.editText1.setVisibility(View.GONE); + mBinder.editText2.setVisibility(View.GONE); + mBinder.included.editText1.setVisibility(View.GONE); + mBinder.included.editText2.setVisibility(View.GONE); + for (View view : views) { + view.setVisibility(View.VISIBLE); + } + } + }); + getInstrumentation().waitForIdleSync(); + } +} diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/CustomNamespaceAdapter.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/CustomNamespaceAdapter.java index 9b8d8bee..1888bb00 100644 --- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/CustomNamespaceAdapter.java +++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/adapter/CustomNamespaceAdapter.java @@ -24,7 +24,7 @@ public class CustomNamespaceAdapter { view.setText(value); } - @BindingAdapter({"bind:set2"}) + @BindingAdapter({"set2"}) public static void setTwo(TextView view, String value) { view.setText(value); } diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/TextViewBindingObject.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/TextViewBindingObject.java index b1d04b69..f57638b2 100644 --- a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/TextViewBindingObject.java +++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/TextViewBindingObject.java @@ -123,6 +123,9 @@ public class TextViewBindingObject extends BindingAdapterBindingObject { @Bindable private float mTextSize = 10f; + @Bindable + private String mText; + public TextView.BufferType getBufferType() { return mBufferType; } @@ -252,6 +255,15 @@ public class TextViewBindingObject extends BindingAdapterBindingObject { return mTextAllCaps; } + public String getText() { + return mText; + } + + public void setText(String text) { + mText = text; + notifyPropertyChanged(BR.text); + } + public void changeValues() { mAutoLink = Linkify.EMAIL_ADDRESSES; mDrawablePadding = 10; diff --git a/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/TwoWayBindingObject.java b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/TwoWayBindingObject.java new file mode 100644 index 00000000..873b1dce --- /dev/null +++ b/integration-tests/TestApp/app/src/main/java/android/databinding/testapp/vo/TwoWayBindingObject.java @@ -0,0 +1,79 @@ +/* + * 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 android.databinding.testapp.vo; + +import android.content.Context; +import android.databinding.ObservableArrayList; +import android.databinding.ObservableArrayMap; +import android.databinding.ObservableBoolean; +import android.databinding.ObservableField; +import android.databinding.ObservableFloat; +import android.databinding.ObservableInt; +import android.databinding.ObservableLong; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; + +import java.util.concurrent.CountDownLatch; + +public class TwoWayBindingObject { + private static final String[] VALUES = { + "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" + }; + public final ListAdapter adapter; + public final ObservableInt selectedItemPosition = new ObservableInt(); + public final ObservableLong date = new ObservableLong(System.currentTimeMillis()); + public final ObservableBoolean checked = new ObservableBoolean(); + public final ObservableInt number = new ObservableInt(1); + public final ObservableFloat rating = new ObservableFloat(1); + public final ObservableInt progress = new ObservableInt(1); + public final ObservableInt currentTab = new ObservableInt(); + public final ObservableField<String> text = new ObservableField<>(); + public final ObservableInt hour = new ObservableInt(); + public final ObservableInt minute = new ObservableInt(); + public final ObservableInt year = new ObservableInt(1972); + public final ObservableInt month = new ObservableInt(9); + public final ObservableInt day = new ObservableInt(21); + public final ObservableArrayList<Integer> list = new ObservableArrayList<>(); + public final ObservableArrayMap<String, Integer> map = new ObservableArrayMap<>(); + public final ObservableField<int[]> array = new ObservableField<>(); + public final ObservableField<CharSequence> editText = new ObservableField<>(); + public int text1Changes; + public int text2Changes; + public CountDownLatch textLatch; + + public TwoWayBindingObject(Context context) { + this.adapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, VALUES); + int[] arr = new int[10]; + for (int i = 0; i < 10; i++) { + list.add(i); + arr[i] = i + 1; + } + array.set(arr); + for (int i = 0; i < VALUES.length; i++) { + map.put(VALUES[i], i + 1); + } + } + + public void textChanged1(CharSequence s, int start, int before, int count) { + text1Changes++; + textLatch.countDown(); + } + + public void textChanged2(CharSequence s, int start, int before, int count) { + text2Changes++; + textLatch.countDown(); + } +} diff --git a/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml b/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml index e9a0e2f9..04beb943 100644 --- a/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml +++ b/integration-tests/TestApp/app/src/main/res/layout/bracket_test.xml @@ -35,7 +35,7 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:id="@+id/indexObj" + android:id="@+id/indexObjView" android:text="@{array[indexObj]}"/> <TextView android:layout_width="wrap_content" diff --git a/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml b/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml index 43b11da0..12aa6ed1 100644 --- a/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml +++ b/integration-tests/TestApp/app/src/main/res/layout/text_view_adapter_test.xml @@ -87,6 +87,10 @@ <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/textWithColor" android:textColor="@{@android:color/holo_blue_bright}" - /> + /> + <EditText android:layout_width="match_parent" android:layout_height="match_parent" + android:id="@+id/twoWayText" + android:text="@={obj.text}" + /> </LinearLayout> -</layout>
\ No newline at end of file +</layout> diff --git a/integration-tests/TestApp/app/src/main/res/layout/two_way.xml b/integration-tests/TestApp/app/src/main/res/layout/two_way.xml new file mode 100644 index 00000000..3ca95888 --- /dev/null +++ b/integration-tests/TestApp/app/src/main/res/layout/two_way.xml @@ -0,0 +1,175 @@ +<?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. + --> + +<layout xmlns:android="http://schemas.android.com/apk/res/android"> + <data> + <variable name="obj" type="android.databinding.testapp.vo.TwoWayBindingObject"/> + </data> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <CalendarView + android:id="@+id/calendarView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:date="@={obj.date}" + /> + <ListView + android:id="@+id/listView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:selectedItemPosition="@={obj.selectedItemPosition}" + android:adapter="@{obj.adapter}" + /> + <CheckBox + android:id="@+id/checkBox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:checked="@={obj.checked}" + android:text="Check Box" + /> + <NumberPicker + android:id="@+id/numberPicker" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:value="@={obj.number}" + android:minValue="@{1}" + android:maxValue="@{100}" + /> + <RatingBar + android:id="@+id/ratingBar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:rating="@={obj.rating}" + android:numStars="5" + /> + <SeekBar + android:id="@+id/seekBar" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:max="100" + android:progress="@={obj.progress}" + /> + <TabHost + android:id="@android:id/tabhost" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:currentTab="@={obj.currentTab}"> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <TabWidget + android:id="@android:id/tabs" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + <FrameLayout + android:id="@android:id/tabcontent" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <View + android:id="@+id/foo" + android:layout_width="10dp" + android:layout_height="10dp"/> + <View + android:id="@+id/bar" + android:layout_width="10dp" + android:layout_height="10dp"/> + </FrameLayout> + </LinearLayout> + </TabHost> + <EditText + android:id="@+id/textView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@={obj.text}" + /> + <TimePicker + android:id="@+id/timePicker" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:hour="@={obj.hour}" + android:minute="@={obj.minute}" + /> + <DatePicker + android:id="@+id/datePicker" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:year="@={obj.year}" + android:month="@={obj.month}" + android:day="@={obj.day}"/> + <DatePicker + android:id="@+id/expressions1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:year="@={obj.year * @integer/oneThousand}" + android:month="@={11 - obj.month}" + android:day="@={obj.day + 1}"/> + <DatePicker + android:id="@+id/expressions2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:year="@={obj.year / @integer/oneThousand}" + android:month="@={@bool/alwaysTrue ? obj.month : obj.day}" + android:day="@={@bool/alwaysFalse ? obj.month : obj.day}"/> + <DatePicker + android:id="@+id/expressions3" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:year="@={obj.list[@integer/one]}" + android:month="@={obj.map[`two`]}" + android:day="@={obj.array[1]}"/> + <DatePicker + android:id="@+id/expressions4" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:year="@={(int)(100000f/obj.year)}" + android:month="@={1 + (obj.month / 2)}" + android:day="@={true ? obj.day : obj.month}"/> + <CheckBox + android:id="@+id/checkBox2" + android:checked="@{!checkBox.checked}" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <CheckBox + android:id="@+id/checkBox3" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <CheckBox + android:id="@+id/checkBox4" + android:checked="@{!checkBox3.checked}" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <include + android:id="@+id/included" + layout="@layout/two_way_included" + android:obj="@{obj}" + android:text="@={obj.text}"/> + <EditText + android:id="@+id/editText1" + android:text="@={obj.editText}" + android:bufferType="editable" + android:onTextChanged="@{obj.textChanged1}" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <EditText + android:id="@+id/editText2" + android:text="@={obj.editText}" + android:bufferType="editable" + android:onTextChanged="@{obj.textChanged2}" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + </LinearLayout> +</layout> diff --git a/integration-tests/TestApp/app/src/main/res/layout/two_way_included.xml b/integration-tests/TestApp/app/src/main/res/layout/two_way_included.xml new file mode 100644 index 00000000..a1a02e02 --- /dev/null +++ b/integration-tests/TestApp/app/src/main/res/layout/two_way_included.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<layout xmlns:android="http://schemas.android.com/apk/res/android"> + <data> + <variable name="text" type="String"/> + <variable name="obj" type="android.databinding.testapp.vo.TwoWayBindingObject"/> + </data> + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <EditText + android:id="@+id/editText1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@={text}"/> + <EditText + android:id="@+id/editText2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@={obj.text}"/> + </LinearLayout> +</layout>
\ No newline at end of file diff --git a/integration-tests/TestApp/app/src/main/res/layout/view_stub.xml b/integration-tests/TestApp/app/src/main/res/layout/view_stub.xml index 322c9668..b6af0fac 100644 --- a/integration-tests/TestApp/app/src/main/res/layout/view_stub.xml +++ b/integration-tests/TestApp/app/src/main/res/layout/view_stub.xml @@ -12,11 +12,9 @@ xmlns:bind="http://schemas.android.com/apk/res-auto"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{firstName}" - android:id="@+id/firstName" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{lastName}" - android:id="@+id/lastName" /> <ViewStub android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/integration-tests/TestApp/app/src/main/res/values/integers.xml b/integration-tests/TestApp/app/src/main/res/values/integers.xml new file mode 100644 index 00000000..b56db93c --- /dev/null +++ b/integration-tests/TestApp/app/src/main/res/values/integers.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <integer name="oneThousand">1000</integer> + <integer name="one">1</integer> +</resources>
\ No newline at end of file diff --git a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java index 68c76c90..bcdcdba1 100644 --- a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java +++ b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java @@ -69,14 +69,6 @@ public class MainActivity extends ActionBarActivity implements Observable { mListeners.notifyChange(this, BR.selected); } - public void onSave(View v) { - if (selected == null) { - return; - } - selected.setName(dataBinder.selectedName.getText().toString()); - selected.setLastName(dataBinder.selectedLastname.getText().toString()); - } - public void onUnselect (View v) { setSelected(null); } diff --git a/samples/BindingDemo/app/src/main/res/layout/main_activity.xml b/samples/BindingDemo/app/src/main/res/layout/main_activity.xml index c16a94f1..e17f27a6 100644 --- a/samples/BindingDemo/app/src/main/res/layout/main_activity.xml +++ b/samples/BindingDemo/app/src/main/res/layout/main_activity.xml @@ -93,7 +93,7 @@ if they are getting complex.--> android:layout_row="0" android:background="@android:color/holo_blue_dark" android:gravity="center" - android:text="@{activity.selected.name}" /> + android:text="@={activity.selected.name}" /> <EditText android:id="@+id/selected_lastname" @@ -104,16 +104,7 @@ if they are getting complex.--> android:layout_row="1" android:background="@android:color/holo_blue_bright" android:gravity="center" - android:text="@{activity.selected.lastName}" /> - <Button - android:id="@+id/edit_button" - android:onClick="@{activity.onSave}" - android:text='@{"Save changes to " + activity.selected.name}' - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_column="1" - android:layout_gravity="right" - android:layout_row="2"/> + android:text="@={activity.selected.lastName}" /> <Button android:id="@+id/delete_button" |