Merge "Re-enable fallbackLineSpacing" into androidx-master-dev
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
index 3a50822..333125a8 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
@@ -75,7 +75,8 @@
* @return [Selection] object which is constructed by combining all Composables that are
* selected.
*/
- private fun mergeSelections(
+ // This function is internal for testing purposes.
+ internal fun mergeSelections(
startPosition: PxPosition,
endPosition: PxPosition,
longPress: Boolean = false,
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt
new file mode 100644
index 0000000..5b4ff27
--- /dev/null
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2019 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 androidx.ui.core.selection
+
+import androidx.test.filters.SmallTest
+import androidx.ui.core.LayoutCoordinates
+import androidx.ui.core.PxPosition
+import androidx.ui.core.px
+import androidx.ui.text.style.TextDirection
+import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
+import com.nhaarman.mockitokotlin2.mock
+import com.nhaarman.mockitokotlin2.spy
+import com.nhaarman.mockitokotlin2.times
+import com.nhaarman.mockitokotlin2.verify
+import com.nhaarman.mockitokotlin2.whenever
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class SelectionManagerDragTest {
+ private val selectionRegistrar = SelectionRegistrarImpl()
+ private val selectable = mock<Selectable>()
+ private val selectionManager = SelectionManager(selectionRegistrar)
+
+ private val containerLayoutCoordinates = mock<LayoutCoordinates>()
+ private val childToLocal_result = PxPosition(300.px, 400.px)
+
+ private val startLayoutCoordinates = mock<LayoutCoordinates>()
+ private val endLayoutCoordinates = mock<LayoutCoordinates>()
+ private val startCoordinates = PxPosition(3.px, 30.px)
+ private val endCoordinates = PxPosition(3.px, 600.px)
+ private val fakeInitialSelection: Selection = Selection(
+ start = Selection.AnchorInfo(
+ coordinates = startCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 0,
+ layoutCoordinates = startLayoutCoordinates
+ ),
+ end = Selection.AnchorInfo(
+ coordinates = endCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 5,
+ layoutCoordinates = endLayoutCoordinates
+ )
+ )
+ private val fakeResultSelection: Selection = Selection(
+ start = Selection.AnchorInfo(
+ coordinates = endCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 5,
+ layoutCoordinates = endLayoutCoordinates
+ ),
+ end = Selection.AnchorInfo(
+ coordinates = startCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 0,
+ layoutCoordinates = startLayoutCoordinates
+ )
+ )
+ private var selection: Selection? = fakeInitialSelection
+ private val lambda: (Selection?) -> Unit = { selection = it }
+ private val spyLambda = spy(lambda)
+
+ @Before
+ fun setup() {
+ selectionRegistrar.subscribe(selectable)
+
+ whenever(
+ containerLayoutCoordinates.childToLocal(
+ child = any(),
+ childLocal = any()
+ )
+ ).thenReturn(childToLocal_result)
+
+ whenever(
+ selectable.getSelection(
+ startPosition = any(),
+ endPosition = any(),
+ containerLayoutCoordinates = any(),
+ longPress = any()
+ )
+ ).thenReturn(fakeResultSelection)
+
+ selectionManager.containerLayoutCoordinates = containerLayoutCoordinates
+ selectionManager.onSelectionChange = spyLambda
+ selectionManager.selection = selection
+ }
+
+ @Test
+ fun handleDragObserver_onStart_startHandle_enable_draggingHandle_get_startHandle_info() {
+ selectionManager.handleDragObserver(isStartHandle = true).onStart(PxPosition.Origin)
+
+ verify(containerLayoutCoordinates, times(1))
+ .childToLocal(
+ child = startLayoutCoordinates,
+ childLocal = getAdjustedCoordinates(startCoordinates)
+ )
+ verify_draggingHandle(expectedDraggingHandleValue = true)
+ verify(spyLambda, times(0)).invoke(fakeResultSelection)
+ }
+
+ @Test
+ fun handleDragObserver_onStart_endHandle_enable_draggingHandle_get_endHandle_info() {
+ selectionManager.handleDragObserver(isStartHandle = false).onStart(PxPosition.Origin)
+
+ verify(containerLayoutCoordinates, times(1))
+ .childToLocal(
+ child = endLayoutCoordinates,
+ childLocal = getAdjustedCoordinates(endCoordinates)
+ )
+ verify_draggingHandle(expectedDraggingHandleValue = true)
+ verify(spyLambda, times(0)).invoke(fakeResultSelection)
+ }
+
+ @Test
+ fun handleDragObserver_onDrag_startHandle_reuse_endHandle_calls_getSelection_change_selection
+ () {
+ val dragDistance = PxPosition(100.px, 100.px)
+ selectionManager.handleDragObserver(isStartHandle = true).onStart(PxPosition.Origin)
+
+ val result = selectionManager.handleDragObserver(isStartHandle = true).onDrag(dragDistance)
+
+ verify(containerLayoutCoordinates, times(1))
+ .childToLocal(
+ child = endLayoutCoordinates,
+ childLocal = getAdjustedCoordinates(endCoordinates)
+ )
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = childToLocal_result + dragDistance,
+ endPosition = childToLocal_result,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = false
+ )
+ assertThat(selection).isEqualTo(fakeResultSelection)
+ verify(spyLambda, times(1)).invoke(fakeResultSelection)
+ assertThat(result).isEqualTo(dragDistance)
+ }
+
+ @Test
+ fun handleDragObserver_onDrag_endHandle_resue_startHandle_calls_getSelection_change_selection
+ () {
+ val dragDistance = PxPosition(100.px, 100.px)
+ selectionManager.handleDragObserver(isStartHandle = false).onStart(PxPosition.Origin)
+
+ val result = selectionManager.handleDragObserver(isStartHandle = false).onDrag(dragDistance)
+
+ verify(containerLayoutCoordinates, times(1))
+ .childToLocal(
+ child = startLayoutCoordinates,
+ childLocal = getAdjustedCoordinates(startCoordinates)
+ )
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = childToLocal_result,
+ endPosition = childToLocal_result + dragDistance,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = false
+ )
+ assertThat(selection).isEqualTo(fakeResultSelection)
+ verify(spyLambda, times(1)).invoke(fakeResultSelection)
+ assertThat(result).isEqualTo(dragDistance)
+ }
+
+ @Test
+ fun handleDragObserver_onStop_disable_draggingHandle() {
+ selectionManager.handleDragObserver(false).onStart(PxPosition.Origin)
+ selectionManager.handleDragObserver(false).onDrag(PxPosition.Origin)
+
+ selectionManager.handleDragObserver(false).onStop(PxPosition.Origin)
+
+ verify_draggingHandle(expectedDraggingHandleValue = false)
+ }
+
+ private fun getAdjustedCoordinates(position: PxPosition): PxPosition {
+ return PxPosition(position.x, position.y - 1.px)
+ }
+
+ private fun verify_draggingHandle(expectedDraggingHandleValue: Boolean) {
+ // Verify draggingHandle is true, by verifying LongPress does nothing. Vice Versa.
+ val position = PxPosition(100.px, 100.px)
+ selectionManager.longPressDragObserver.onLongPress(position)
+ verify(selectable, times(if (expectedDraggingHandleValue) 0 else 1))
+ .getSelection(
+ startPosition = position,
+ endPosition = position,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = true
+ )
+ }
+}
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt
new file mode 100644
index 0000000..dd309f8
--- /dev/null
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2019 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 androidx.ui.core.selection
+
+import androidx.test.filters.SmallTest
+import androidx.ui.core.LayoutCoordinates
+import androidx.ui.core.PxPosition
+import androidx.ui.core.px
+import androidx.ui.text.style.TextDirection
+import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
+import com.nhaarman.mockitokotlin2.mock
+import com.nhaarman.mockitokotlin2.spy
+import com.nhaarman.mockitokotlin2.times
+import com.nhaarman.mockitokotlin2.verify
+import com.nhaarman.mockitokotlin2.whenever
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class SelectionManagerLongPressDragTest {
+ private val selectionRegistrar = SelectionRegistrarImpl()
+ private val selectable = mock<Selectable>()
+ private val selectionManager = SelectionManager(selectionRegistrar)
+
+ private val startLayoutCoordinates = mock<LayoutCoordinates>()
+ private val endLayoutCoordinates = mock<LayoutCoordinates>()
+ private val startCoordinates = PxPosition(3.px, 30.px)
+ private val endCoordinates = PxPosition(3.px, 600.px)
+ private val fakeInitialSelection: Selection = Selection(
+ start = Selection.AnchorInfo(
+ coordinates = startCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 0,
+ layoutCoordinates = startLayoutCoordinates
+ ),
+ end = Selection.AnchorInfo(
+ coordinates = endCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 5,
+ layoutCoordinates = endLayoutCoordinates
+ )
+ )
+
+ private val fakeResultSelection: Selection = Selection(
+ start = Selection.AnchorInfo(
+ coordinates = endCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 5,
+ layoutCoordinates = endLayoutCoordinates
+ ),
+ end = Selection.AnchorInfo(
+ coordinates = startCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 0,
+ layoutCoordinates = startLayoutCoordinates
+ )
+ )
+
+ private var selection: Selection? = null
+ private val lambda: (Selection?) -> Unit = { selection = it }
+ private val spyLambda = spy(lambda)
+
+ @Before
+ fun setup() {
+ val containerLayoutCoordinates = mock<LayoutCoordinates>()
+ selectionRegistrar.subscribe(selectable)
+
+ whenever(
+ selectable.getSelection(
+ startPosition = any(),
+ endPosition = any(),
+ containerLayoutCoordinates = any(),
+ longPress = any()
+ )
+ ).thenReturn(fakeResultSelection)
+
+ selectionManager.containerLayoutCoordinates = containerLayoutCoordinates
+ selectionManager.onSelectionChange = spyLambda
+ selectionManager.selection = selection
+ }
+
+ @Test
+ fun longPressDragObserver_onLongPress_calls_getSelection_change_selection() {
+ val position = PxPosition(100.px, 100.px)
+
+ selectionManager.longPressDragObserver.onLongPress(position)
+
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = position,
+ endPosition = position,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = true
+ )
+ assertThat(selection).isEqualTo(fakeResultSelection)
+ verify(spyLambda, times(1)).invoke(fakeResultSelection)
+ }
+
+ @Test
+ fun longPressDragObserver_onDragStart_reset_dragTotalDistance() {
+ // Setup. Make sure selectionManager.dragTotalDistance is not 0.
+ val dragDistance1 = PxPosition(15.px, 10.px)
+ val beginPosition1 = PxPosition(30.px, 20.px)
+ val dragDistance2 = PxPosition(100.px, 300.px)
+ val beginPosition2 = PxPosition(300.px, 200.px)
+ selectionManager.longPressDragObserver.onLongPress(beginPosition1)
+ selectionManager.longPressDragObserver.onDragStart()
+ selectionManager.longPressDragObserver.onDrag(dragDistance1)
+ // Setup. Cancel selection and reselect.
+ selectionManager.onRelease()
+ // Start the new selection
+ selectionManager.longPressDragObserver.onLongPress(beginPosition2)
+ selectionManager.selection = fakeInitialSelection
+ selection = fakeInitialSelection
+
+ // Act. Reset selectionManager.dragTotalDistance to zero.
+ selectionManager.longPressDragObserver.onDragStart()
+ selectionManager.longPressDragObserver.onDrag(dragDistance2)
+
+ // Verify.
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = beginPosition2,
+ endPosition = beginPosition2 + dragDistance2,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = true
+ )
+ assertThat(selection).isEqualTo(fakeResultSelection)
+ verify(spyLambda, times(3)).invoke(fakeResultSelection)
+ }
+
+ @Test
+ fun longPressDragObserver_onDrag_calls_getSelection_change_selection() {
+ val dragDistance = PxPosition(15.px, 10.px)
+ val beginPosition = PxPosition(30.px, 20.px)
+ selectionManager.longPressDragObserver.onLongPress(beginPosition)
+ selectionManager.selection = fakeInitialSelection
+ selection = fakeInitialSelection
+ selectionManager.longPressDragObserver.onDragStart()
+
+ val result = selectionManager.longPressDragObserver.onDrag(dragDistance)
+
+ assertThat(result).isEqualTo(dragDistance)
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = beginPosition,
+ endPosition = beginPosition + dragDistance,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = true
+ )
+ assertThat(selection).isEqualTo(fakeResultSelection)
+ verify(spyLambda, times(2)).invoke(fakeResultSelection)
+ }
+
+ @Test
+ fun longPressDragObserver_onDrag_directly_not_call_getSelection_not_change_selection() {
+ val dragDistance = PxPosition(15.px, 10.px)
+ val beginPosition = PxPosition(30.px, 20.px)
+
+ selection = fakeInitialSelection
+ val result = selectionManager.longPressDragObserver.onDrag(dragDistance)
+
+ assertThat(result).isEqualTo(PxPosition.Origin)
+ verify(selectable, times(0))
+ .getSelection(
+ startPosition = beginPosition,
+ endPosition = beginPosition + dragDistance,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = true
+ )
+ assertThat(selection).isEqualTo(fakeInitialSelection)
+ verify(spyLambda, times(0)).invoke(fakeResultSelection)
+ }
+}
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt
new file mode 100644
index 0000000..dbd4c94
--- /dev/null
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2019 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 androidx.ui.core.selection
+
+import androidx.test.filters.SmallTest
+import androidx.ui.core.LayoutCoordinates
+import androidx.ui.core.PxPosition
+import androidx.ui.core.px
+import androidx.ui.text.style.TextDirection
+import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.mock
+import com.nhaarman.mockitokotlin2.spy
+import com.nhaarman.mockitokotlin2.times
+import com.nhaarman.mockitokotlin2.verify
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class SelectionManagerTest {
+ private val selectionRegistrar = SelectionRegistrarImpl()
+ private val selectable = mock<Selectable>()
+ private val selectionManager = SelectionManager(selectionRegistrar)
+
+ private val startLayoutCoordinates = mock<LayoutCoordinates>()
+ private val endLayoutCoordinates = mock<LayoutCoordinates>()
+ private val startCoordinates = PxPosition(3.px, 30.px)
+ private val endCoordinates = PxPosition(3.px, 600.px)
+
+ @Before
+ fun setup() {
+ val containerLayoutCoordinates = mock<LayoutCoordinates>()
+ selectionRegistrar.subscribe(selectable)
+ selectionManager.containerLayoutCoordinates = containerLayoutCoordinates
+ }
+
+ @Test
+ fun mergeSelections_single_selectable_calls_getSelection_once() {
+ selectionManager.mergeSelections(
+ startPosition = startCoordinates,
+ endPosition = endCoordinates
+ )
+
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = startCoordinates,
+ endPosition = endCoordinates,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = false
+ )
+ }
+
+ @Test
+ fun mergeSelections_multiple_selectables_calls_getSelection_multiple_times() {
+ val selectable_another = mock<Selectable>()
+ selectionRegistrar.subscribe(selectable_another)
+
+ selectionManager.mergeSelections(
+ startPosition = startCoordinates,
+ endPosition = endCoordinates
+ )
+
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = startCoordinates,
+ endPosition = endCoordinates,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = false
+ )
+ verify(selectable_another, times(1))
+ .getSelection(
+ startPosition = startCoordinates,
+ endPosition = endCoordinates,
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = false
+ )
+ }
+
+ @Test
+ fun cancel_selection_calls_getSelection_selection_becomes_null() {
+ val fakeSelection =
+ Selection(
+ start = Selection.AnchorInfo(
+ coordinates = startCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 0,
+ layoutCoordinates = startLayoutCoordinates
+ ),
+ end = Selection.AnchorInfo(
+ coordinates = endCoordinates,
+ direction = TextDirection.Ltr,
+ offset = 5,
+ layoutCoordinates = endLayoutCoordinates
+ )
+ )
+ var selection: Selection? = fakeSelection
+ val lambda: (Selection?) -> Unit = { selection = it }
+ val spyLambda = spy(lambda)
+ selectionManager.onSelectionChange = spyLambda
+ selectionManager.selection = fakeSelection
+
+ selectionManager.onRelease()
+
+ verify(selectable, times(1))
+ .getSelection(
+ startPosition = PxPosition((-1).px, (-1).px),
+ endPosition = PxPosition((-1).px, (-1).px),
+ containerLayoutCoordinates = selectionManager.containerLayoutCoordinates,
+ longPress = false
+ )
+ assertThat(selection).isNull()
+ verify(spyLambda, times(1)).invoke(null)
+ }
+}