diff --git a/CompanionPane/build.gradle b/CompanionPane/build.gradle index 553577f5..012854ac 100644 --- a/CompanionPane/build.gradle +++ b/CompanionPane/build.gradle @@ -30,7 +30,8 @@ dependencies { implementation androidxDependencies.ktxCore implementation androidxDependencies.ktxFragment - implementation microsoftDependencies.dualScreenLayout + implementation microsoftDependencies.screenManager + implementation microsoftDependencies.layouts testImplementation testDependencies.junit diff --git a/CompanionPane/src/androidTest/java/com/microsoft/device/display/samples/companionpane/LayoutOrientationTest.kt b/CompanionPane/src/androidTest/java/com/microsoft/device/display/samples/companionpane/LayoutOrientationTest.kt index 320dfac3..2647c8ea 100644 --- a/CompanionPane/src/androidTest/java/com/microsoft/device/display/samples/companionpane/LayoutOrientationTest.kt +++ b/CompanionPane/src/androidTest/java/com/microsoft/device/display/samples/companionpane/LayoutOrientationTest.kt @@ -27,7 +27,7 @@ class LayoutOrientationTest { private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) @get:Rule - val activityRule = ActivityTestRule(MainActivity::class.java) + val activityRule = ActivityTestRule(MainActivity::class.java) @After fun resetOrientation() { @@ -37,7 +37,7 @@ class LayoutOrientationTest { @Test fun shouldFindLayout_whenInSinglePortrait() { - onView(withId(R.id.single_screen_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) onView(withId(R.id.single_screen_layout_port)).check(matches(isDisplayed())) } @@ -45,7 +45,7 @@ class LayoutOrientationTest { fun shouldFindLayout_whenInSingleLandscape() { rotateDevice() - onView(withId(R.id.single_screen_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) onView(withId(R.id.single_screen_layout_land)).check(matches(isDisplayed())) } @@ -53,11 +53,11 @@ class LayoutOrientationTest { fun shouldFindLayouts_whenInDoublePortrait() { spanApplication() - onView(withId(R.id.dual_screen_start_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.picture_dual_layout)).check(matches(isDisplayed())) + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.dual_screen_layout_land_start)).check(matches(isDisplayed())) - onView(withId(R.id.dual_screen_end_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.tools_dual_layout_land)).check(matches(isDisplayed())) + onView(withId(R.id.second_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.dual_screen_layout_land_end)).check(matches(isDisplayed())) } @Test @@ -65,33 +65,17 @@ class LayoutOrientationTest { spanApplication() rotateDevice() - onView(withId(R.id.dual_screen_start_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.picture_dual_layout)).check(matches(isDisplayed())) + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.dual_screen_layout_port_start)).check(matches(isDisplayed())) - onView(withId(R.id.dual_screen_end_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.tools_dual_layout_port)).check(matches(isDisplayed())) - } - - @Test - fun shouldFindLayouts_whenSpanningInDoubleLandscape() { - rotateDevice() - spanLandscapeApplication() - - onView(withId(R.id.dual_screen_start_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.picture_dual_layout)).check(matches(isDisplayed())) - - onView(withId(R.id.dual_screen_end_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.tools_dual_layout_port)).check(matches(isDisplayed())) + onView(withId(R.id.second_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.dual_screen_layout_port_end)).check(matches(isDisplayed())) } private fun spanApplication() { device.swipe(675, 1780, 1350, 900, 400) } - private fun spanLandscapeApplication() { - device.swipe(1780, 2100, 1350, 1500, 400) - } - private fun rotateDevice() { device.setOrientationLeft() } diff --git a/CompanionPane/src/main/res/layout-land/dual_screen_layout_end.xml b/CompanionPane/src/main/res/layout-land/dual_screen_layout_end.xml index 4f353044..824788b7 100644 --- a/CompanionPane/src/main/res/layout-land/dual_screen_layout_end.xml +++ b/CompanionPane/src/main/res/layout-land/dual_screen_layout_end.xml @@ -6,7 +6,7 @@ --> - - - - - \ No newline at end of file + app:tools_screen_mode="dual_screen" /> \ No newline at end of file diff --git a/HingeAngle/src/main/res/layout/fragment_dual_screen.xml b/HingeAngle/src/main/res/layout/fragment_dual_screen.xml index adc57fa2..225bf8da 100644 --- a/HingeAngle/src/main/res/layout/fragment_dual_screen.xml +++ b/HingeAngle/src/main/res/layout/fragment_dual_screen.xml @@ -1,9 +1,6 @@ diff --git a/HingeAngle/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/HingeAngle/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 09902b3d..da870be2 100644 --- a/HingeAngle/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/HingeAngle/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,9 +1,6 @@ diff --git a/HingeAngle/src/main/res/values/attrs_pen_draw_view.xml b/HingeAngle/src/main/res/values/attrs_pen_draw_view.xml index fcf1925a..d7382cb4 100644 --- a/HingeAngle/src/main/res/values/attrs_pen_draw_view.xml +++ b/HingeAngle/src/main/res/values/attrs_pen_draw_view.xml @@ -1,8 +1,5 @@ diff --git a/HingeAngle/src/main/res/values/colors.xml b/HingeAngle/src/main/res/values/colors.xml index 181624e7..d6d90dfc 100644 --- a/HingeAngle/src/main/res/values/colors.xml +++ b/HingeAngle/src/main/res/values/colors.xml @@ -1,9 +1,6 @@ diff --git a/HingeAngle/src/main/res/values/strings.xml b/HingeAngle/src/main/res/values/strings.xml index d3da7fff..a4501808 100644 --- a/HingeAngle/src/main/res/values/strings.xml +++ b/HingeAngle/src/main/res/values/strings.xml @@ -1,8 +1,5 @@ diff --git a/HingeAngle/src/main/res/values/styles.xml b/HingeAngle/src/main/res/values/styles.xml index 9a8df0b2..5f6f145b 100644 --- a/HingeAngle/src/main/res/values/styles.xml +++ b/HingeAngle/src/main/res/values/styles.xml @@ -1,8 +1,5 @@ diff --git a/ListDetail/build.gradle b/ListDetail/build.gradle index cb61f041..3c14fbc1 100644 --- a/ListDetail/build.gradle +++ b/ListDetail/build.gradle @@ -23,6 +23,10 @@ android { } dependencies { + implementation microsoftDependencies.screenManager + implementation microsoftDependencies.layouts + implementation microsoftDependencies.fragmentsHandler + implementation kotlinDependencies.kotlinStdlib implementation androidxDependencies.appCompat implementation androidxDependencies.constraintLayout @@ -30,14 +34,11 @@ dependencies { implementation androidxDependencies.ktxFragment implementation androidxDependencies.recyclerView -// TODO: temporary change, will be updated in the next PR -// implementation microsoftDependencies.dualScreenLayout - implementation "com.microsoft.device.dualscreen:layouts:1.0.0-alpha02" - testImplementation testDependencies.junit androidTestImplementation instrumentationTestDependencies.junit androidTestImplementation instrumentationTestDependencies.espressoCore + androidTestImplementation instrumentationTestDependencies.espressoContrib androidTestImplementation instrumentationTestDependencies.uiAutomator androidTestImplementation instrumentationTestDependencies.testRules } diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsInDualScreenModeTest.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsInDualScreenModeTest.kt new file mode 100644 index 00000000..75498fbf --- /dev/null +++ b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsInDualScreenModeTest.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ + +package com.microsoft.device.display.samples.listdetail + +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.filters.LargeTest +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner +import androidx.test.rule.ActivityTestRule +import com.microsoft.device.display.samples.listdetail.utils.forceClick +import com.microsoft.device.display.samples.listdetail.utils.hasDrawable +import com.microsoft.device.display.samples.listdetail.utils.setOrientationLeft +import com.microsoft.device.display.samples.listdetail.utils.setOrientationRight +import com.microsoft.device.display.samples.listdetail.utils.switchFromSingleToDualScreen +import com.microsoft.device.display.samples.listdetail.utils.unfreezeRotation +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4ClassRunner::class) +@LargeTest +class ListDetailsInDualScreenModeTest { + @get:Rule + val activityRule = ActivityTestRule(MainActivity::class.java) + + @After + fun tearDown() { + unfreezeRotation() + } + + @Test + fun displayListAndDetails() { + switchFromSingleToDualScreen() + + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.image_list)).check(matches(isDisplayed())) + + onView(withId(R.id.image_list)).perform(actionOnItemAtPosition(2, forceClick())) + onView(withId(R.id.imageView)).check(matches(isDisplayed())).check(matches(hasDrawable(R.drawable.image_3))) + } + + @Test + fun displayListAndDetailsWithRotationLeft() { + setOrientationLeft() + displayListAndDetails() + } + + @Test + fun displayListAndDetailsWithRotationRight() { + setOrientationRight() + displayListAndDetails() + } +} \ No newline at end of file diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsInSingleScreenModeTest.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsInSingleScreenModeTest.kt new file mode 100644 index 00000000..b7789a44 --- /dev/null +++ b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsInSingleScreenModeTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ + +package com.microsoft.device.display.samples.listdetail + +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.filters.LargeTest +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner +import androidx.test.rule.ActivityTestRule +import com.microsoft.device.display.samples.listdetail.utils.forceClick +import com.microsoft.device.display.samples.listdetail.utils.hasDrawable +import com.microsoft.device.display.samples.listdetail.utils.setOrientationLeft +import com.microsoft.device.display.samples.listdetail.utils.unfreezeRotation +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4ClassRunner::class) +@LargeTest +class ListDetailsInSingleScreenModeTest { + @get:Rule + val activityRule = ActivityTestRule(MainActivity::class.java) + + @After + fun tearDown() { + unfreezeRotation() + } + + @Test + fun openDetailsFromList() { + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.image_list)).check(matches(isDisplayed())) + + onView(withId(R.id.image_list)).perform(actionOnItemAtPosition(1, forceClick())) + onView(withId(R.id.imageView)).check(matches(isDisplayed())).check(matches(hasDrawable(R.drawable.image_2))) + } + + @Test + fun openDetailsFromListWithRotationLeft() { + setOrientationLeft() + openDetailsFromList() + } + + @Test + fun openDetailsFromListWithRotationRight() { + setOrientationLeft() + openDetailsFromList() + } +} diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsSwitchScreenModeTest.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsSwitchScreenModeTest.kt new file mode 100644 index 00000000..cec6edf8 --- /dev/null +++ b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsSwitchScreenModeTest.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ + +package com.microsoft.device.display.samples.listdetail + +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.filters.LargeTest +import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner +import androidx.test.rule.ActivityTestRule +import com.microsoft.device.display.samples.listdetail.utils.forceClick +import com.microsoft.device.display.samples.listdetail.utils.hasDrawable +import com.microsoft.device.display.samples.listdetail.utils.setOrientationLeft +import com.microsoft.device.display.samples.listdetail.utils.setOrientationRight +import com.microsoft.device.display.samples.listdetail.utils.switchFromDualToSingleScreen +import com.microsoft.device.display.samples.listdetail.utils.switchFromSingleToDualScreen +import com.microsoft.device.display.samples.listdetail.utils.unfreezeRotation +import org.junit.After +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4ClassRunner::class) +@LargeTest +class ListDetailsSwitchScreenModeTest { + @get:Rule + val activityRule = ActivityTestRule(MainActivity::class.java) + + @After + fun tearDown() { + unfreezeRotation() + } + + @Test + fun testSwitchScreenMode() { + checkInSingleScreenMode() + switchFromSingleToDualScreen() + checkInDualScreenMode() + switchFromDualToSingleScreen() + checkInSingleScreenMode() + } + + @Test + fun testSwitchScreenModeWithOrientationLeft() { + setOrientationLeft() + checkInSingleScreenMode() + switchFromSingleToDualScreen() + checkInSingleScreenMode() + switchFromDualToSingleScreen() + checkInSingleScreenMode() + } + + @Test + fun testSwitchScreenModeWithOrientationRight() { + setOrientationRight() + checkInSingleScreenMode() + switchFromSingleToDualScreen() + checkInSingleScreenMode() + switchFromDualToSingleScreen() + checkInSingleScreenMode() + } + + private fun checkInSingleScreenMode() { + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.image_list)).check(matches(isDisplayed())) + + onView(withId(R.id.image_list)).perform(actionOnItemAtPosition(1, forceClick())) + onView(withId(R.id.imageView)).check(matches(isDisplayed())).check(matches(hasDrawable(R.drawable.image_2))) + } + + private fun checkInDualScreenMode() { + onView(withId(R.id.first_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.second_container_id)).check(matches(isDisplayed())) + onView(withId(R.id.image_list)).check(matches(isDisplayed())) + + onView(withId(R.id.image_list)).perform(actionOnItemAtPosition(2, forceClick())) + onView(withId(R.id.imageView)).check(matches(isDisplayed())).check(matches(hasDrawable(R.drawable.image_3))) + } +} \ No newline at end of file diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsTest.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsTest.kt deleted file mode 100644 index dbc49b52..00000000 --- a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/ListDetailsTest.kt +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. - * - */ - -package com.microsoft.device.display.samples.listdetail - -import android.view.View -import android.widget.ListView -import androidx.test.espresso.Espresso.onData -import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.BoundedMatcher -import androidx.test.espresso.matcher.ViewMatchers.isDisplayed -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withText -import androidx.test.filters.LargeTest -import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.rule.ActivityTestRule -import androidx.test.uiautomator.UiDevice -import org.hamcrest.Description -import org.hamcrest.Matcher -import org.hamcrest.Matchers.hasToString -import org.hamcrest.core.AllOf.allOf -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4ClassRunner::class) -@LargeTest -class ListDetailsTest { - private val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - @get:Rule - val activityRule = ActivityTestRule(MainActivity::class.java) - - @Test - fun openDetailsFromList_whenInSingleMode() { - onView(withId(R.id.single_screen_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.list_view)).check(matches(isDisplayed())) - - onData(hasToString("Item 2")) - .inAdapterView(withId(R.id.list_view)) - .perform(click()) - - onView(allOf(withId(R.id.tvTitle), withText("Item 2"))).check(matches(isDisplayed())) - } - - @Test - fun displayListAndDetails_whenInDualMode() { - spanApplication() - - onView(withId(R.id.dual_screen_start_container_id)).check(matches(isDisplayed())) - onView(withId(R.id.dual_screen_end_container_id)).check(matches(isDisplayed())) - - onView(withId(R.id.list_view)).check(matches(isDisplayed())) - onView(withId(R.id.tvTitle)).check(matches(isDisplayed())) - } - - @Test - fun checkLinkBetweenListAndDetail_whenInDualMode() { - spanApplication() - - onView(withId(R.id.list_view)).check(matches(isDisplayed())) - - onData(hasToString("Item 2")) - .inAdapterView(withId(R.id.list_view)) - .perform(click()) - - onView(withId(R.id.list_view)).check(matches(isItemChecked(1))) - onView(allOf(withId(R.id.tvTitle), withText("Item 2"))).check(matches(isDisplayed())) - } - - private fun spanApplication() { - device.swipe(675, 1780, 1350, 900, 400) - } - - companion object { - fun isItemChecked(itemPosition: Int): Matcher = - object : BoundedMatcher(ListView::class.java) { - override fun describeTo(description: Description?) { - description?.appendText( - "Check if item from position $itemPosition is checked" - ) - } - - override fun matchesSafely(listView: ListView?): Boolean { - return listView?.isItemChecked(itemPosition) == true - } - } - } -} diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/DrawableMatcher.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/DrawableMatcher.kt new file mode 100644 index 00000000..c06904c7 --- /dev/null +++ b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/DrawableMatcher.kt @@ -0,0 +1,52 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ + +package com.microsoft.device.display.samples.listdetail.utils + +import android.graphics.drawable.BitmapDrawable +import android.view.View +import android.widget.ImageView +import androidx.core.content.ContextCompat +import org.hamcrest.Description +import org.hamcrest.TypeSafeMatcher + +/** + * A matcher that matches {@link ImageView}s based on its drawable background id. + */ +class DrawableMatcher(private val drawableId: Int) : TypeSafeMatcher(View::class.java) { + private var resourceName: String? = null + + override fun matchesSafely(target: View?): Boolean { + if (target == null) { + return false + } + + if (target !is ImageView) { + return false + } + + if (drawableId < 0) { + return target.drawable == null + } + + resourceName = target.getContext().resources.getResourceEntryName(drawableId) + + val expectedDrawable = ContextCompat.getDrawable(target.context, drawableId) ?: return false + val targetBitmap = (target.drawable as BitmapDrawable).bitmap + val expectedBitmap = (expectedDrawable as BitmapDrawable).bitmap + return targetBitmap.sameAs(expectedBitmap) + } + + override fun describeTo(description: Description) { + description.appendText("with drawable from resource id: ") + description.appendValue(drawableId) + resourceName?.let { + description.appendText("[") + description.appendText(it) + description.appendText("]") + } + } +} \ No newline at end of file diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/ForceClick.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/ForceClick.kt new file mode 100644 index 00000000..a584a6f0 --- /dev/null +++ b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/ForceClick.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ + +package com.microsoft.device.display.samples.listdetail.utils + +import android.view.View +import androidx.test.espresso.UiController +import androidx.test.espresso.ViewAction +import androidx.test.espresso.matcher.ViewMatchers.isClickable +import androidx.test.espresso.matcher.ViewMatchers.isEnabled +import org.hamcrest.Matcher +import org.hamcrest.Matchers.allOf + +/** + * Click action for a view without to check the coordinates for the view on the screen. when device is rotated. + */ +class ForceClick : ViewAction { + override fun getConstraints(): Matcher { + return allOf(isClickable(), isEnabled()) + } + + override fun getDescription(): String { + return "force click" + } + + override fun perform(uiController: UiController?, view: View?) { + view?.performClick() + uiController?.loopMainThreadUntilIdle() + } +} \ No newline at end of file diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/SurfaceDuoUtils.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/SurfaceDuoUtils.kt new file mode 100644 index 00000000..ace27279 --- /dev/null +++ b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/SurfaceDuoUtils.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + */ + +package com.microsoft.device.display.samples.listdetail.utils + +import android.graphics.Rect +import android.view.Surface +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice + +val START_SCREEN_RECT = Rect(0, 0, 1350, 1800) +val END_SCREEN_RECT = Rect(1434, 0, 2784, 1800) + +val SINGLE_SCREEN_WINDOW_RECT = START_SCREEN_RECT +val DUAL_SCREEN_WINDOW_RECT = Rect(0, 0, 2784, 1800) + +val SINGLE_SCREEN_HINGE_RECT = Rect() +val DUAL_SCREEN_HINGE_RECT = Rect(1350, 0, 1434, 1800) + +/** + * Switches application from single screen mode to dual screen mode + */ +fun switchFromSingleToDualScreen() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + when (device.displayRotation) { + Surface.ROTATION_0 -> device.swipe(675, 1780, 1350, 900, 400) + Surface.ROTATION_270 -> device.swipe(1780, 675, 900, 1350, 400) + Surface.ROTATION_90 -> device.swipe(1780, 2109, 900, 1400, 400) + } +} + +/** + * Switches application from dual screen mode to single screen + */ +fun switchFromDualToSingleScreen() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + when (device.displayRotation) { + Surface.ROTATION_0 -> device.swipe(1500, 1780, 650, 900, 400) + Surface.ROTATION_270 -> device.swipe(1780, 1500, 900, 650, 400) + Surface.ROTATION_90 -> device.swipe(1780, 1250, 900, 1500, 400) + } +} + +/** + * Re-enables the sensors and un-freezes the device rotation allowing its contents + * to rotate with the device physical rotation. During a test execution, it is best to + * keep the device frozen in a specific orientation until the test case execution has completed. + */ +fun unfreezeRotation() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.unfreezeRotation() +} + +/** + * Simulates orienting the device to the left and also freezes rotation + * by disabling the sensors. + */ +fun setOrientationLeft() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.setOrientationLeft() +} + +/** + * Simulates orienting the device into its natural orientation and also freezes rotation + * by disabling the sensors. + */ +fun setOrientationNatural() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.setOrientationNatural() +} + +/** + * Simulates orienting the device to the right and also freezes rotation + * by disabling the sensors. + */ +fun setOrientationRight() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.setOrientationRight() +} \ No newline at end of file diff --git a/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/TestUtils.kt b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/TestUtils.kt new file mode 100644 index 00000000..56764e9f --- /dev/null +++ b/ListDetail/src/androidTest/java/com/microsoft/device/display/samples/listdetail/utils/TestUtils.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + */ + +package com.microsoft.device.display.samples.listdetail.utils + +import androidx.test.espresso.ViewAction + +/** + * Returns an action that clicks the view without to check the coordinates on the screen. + * Seems that ViewActions.click() finds coordinates of the view on the screen, and then performs the tap on the coordinates. + * Seems tha changing the screen rotations affects these coordinates and ViewActions.click() throws exceptions. + */ +fun forceClick(): ViewAction = ForceClick() + +/** + * Returns a matcher that matches {@link ImageViews Views} that has the expected drawable background. + * @param drawableId The expected Drawable resource id + */ +fun hasDrawable(drawableId: Int) = DrawableMatcher(drawableId) \ No newline at end of file diff --git a/ListDetail/src/main/AndroidManifest.xml b/ListDetail/src/main/AndroidManifest.xml index 742b875a..68746b4c 100644 --- a/ListDetail/src/main/AndroidManifest.xml +++ b/ListDetail/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - - - - - - - \ No newline at end of file + android:layout_height="match_parent" + app:is_dual_landscape_single_container="true" + app:is_dual_portrait_single_container="true" + app:dual_landscape_single_layout_id="@layout/double_landscape_layout" + app:dual_portrait_single_layout_id="@layout/single_screen_layout" + app:single_screen_layout_id="@layout/single_screen_layout" + app:tools_screen_mode="dual_screen" /> \ No newline at end of file diff --git a/TwoPage/src/main/res/layout/double_landscape_layout.xml b/TwoPage/src/main/res/layout/double_landscape_layout.xml index baa3ab3f..58fdda4d 100644 --- a/TwoPage/src/main/res/layout/double_landscape_layout.xml +++ b/TwoPage/src/main/res/layout/double_landscape_layout.xml @@ -1,16 +1,10 @@ - - - - - \ No newline at end of file + android:layout_height="match_parent" /> diff --git a/TwoPage/src/main/res/layout/single_screen_layout.xml b/TwoPage/src/main/res/layout/single_screen_layout.xml new file mode 100644 index 00000000..9d49a6da --- /dev/null +++ b/TwoPage/src/main/res/layout/single_screen_layout.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/TwoPage/src/main/res/values/colors.xml b/TwoPage/src/main/res/values/colors.xml index f1fd0100..7d4c4ac4 100644 --- a/TwoPage/src/main/res/values/colors.xml +++ b/TwoPage/src/main/res/values/colors.xml @@ -9,4 +9,5 @@ #008577 #00574B #D81B60 + #000000 diff --git a/build.gradle b/build.gradle index 248a00b0..326716be 100644 --- a/build.gradle +++ b/build.gradle @@ -9,8 +9,8 @@ buildscript { apply from: 'dependencies.gradle' - ext.kotlin_version = '1.3.71' - + ext.kotlin_version = ext.kotlinVersion + repositories { google() jcenter() @@ -27,10 +27,6 @@ allprojects { repositories { google() jcenter() - - maven { - url config.duoSdkUrl - } } apply from: "$rootDir/ktlint.gradle" diff --git a/dependencies.gradle b/dependencies.gradle index 6612872f..0f96d8ef 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -5,21 +5,17 @@ */ ext { - gradlePluginVersion = "3.6.3" - kotlinVersion = "1.3.72" + gradlePluginVersion = "4.1.1" + kotlinVersion = "1.4.21" compileSdkVersion = 29 buildToolsVersion = '29.0.2' targetSdkVersion = compileSdkVersion minSdkVersion = compileSdkVersion - //Surface Duo - duo_url = "https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1" - config = [ + duoSdkVersion : "1.0.0-beta1", gradlePlugin : "com.android.tools.build:gradle:$gradlePluginVersion", kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion", - duoSdkUrl : - "https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1", testInstrumentationRunner: "androidx.test.runner.AndroidJUnitRunner" ] @@ -38,13 +34,13 @@ ext { localBroadcastManagerVersion = "1.0.0" androidxDependencies = [ - appCompat : "androidx.appcompat:appcompat:$appCompatVersion", - constraintLayout: "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion", - recyclerView : "androidx.recyclerview:recyclerview:$recyclerViewVersion", - cardView : "androidx.cardview:cardview:$cardViewVersion", - ktxCore : "androidx.core:core-ktx:$ktxCoreVersion", - ktxFragment : "androidx.fragment:fragment-ktx:$ktxFragmentVersion", - viewPager2 : "androidx.viewpager2:viewpager2:$viewPager2Version", + appCompat : "androidx.appcompat:appcompat:$appCompatVersion", + constraintLayout : "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion", + recyclerView : "androidx.recyclerview:recyclerview:$recyclerViewVersion", + cardView : "androidx.cardview:cardview:$cardViewVersion", + ktxCore : "androidx.core:core-ktx:$ktxCoreVersion", + ktxFragment : "androidx.fragment:fragment-ktx:$ktxFragmentVersion", + viewPager2 : "androidx.viewpager2:viewpager2:$viewPager2Version", locaBroadcastManager: "androidx.localbroadcastmanager:localbroadcastmanager:$localBroadcastManagerVersion", ] @@ -57,18 +53,32 @@ ext { //Microsoft dependencies version dualScreenLayoutVersion = "1.0.0-alpha01" + screenManagerWindowManagerVersion = config.duoSdkVersion + screenManagerDisplayMaskVersion = config.duoSdkVersion + fragmentsHandlerVersion = config.duoSdkVersion + layoutsVersion = config.duoSdkVersion + bottomNavigationVersion = config.duoSdkVersion + recyclerViewVersion = config.duoSdkVersion + tabsVersion = config.duoSdkVersion microsoftDependencies = [ - dualScreenLayout: "com.microsoft.device:dualscreen-layout:$dualScreenLayoutVersion" + screenManagerWindowManager: "com.microsoft.device.dualscreen:screenmanager-windowmanager:$screenManagerWindowManagerVersion", + screenManagerDisplayMask : "com.microsoft.device.dualscreen:screenmanager-displaymask:$screenManagerDisplayMaskVersion", + fragmentsHandler : "com.microsoft.device.dualscreen:fragmentshandler:$fragmentsHandlerVersion", + layouts : "com.microsoft.device.dualscreen:layouts:$layoutsVersion", + bottomNavigation : "com.microsoft.device.dualscreen:bottomnavigation:$bottomNavigationVersion", + recyclerView : "com.microsoft.device.dualscreen:recyclerview:$recyclerViewVersion", + tabs : "com.microsoft.device.dualscreen:tabs:$tabsVersion" ] + microsoftDependencies["screenManager"] = microsoftDependencies.screenManagerWindowManager //Test dependencies version junitVersion = "4.13" mockitoVersion = "3.5.9" testDependencies = [ - junit : "junit:junit:$junitVersion", - mockito : "org.mockito:mockito-core:$mockitoVersion", + junit : "junit:junit:$junitVersion", + mockito: "org.mockito:mockito-core:$mockitoVersion", ] //Android test dependencies version @@ -81,13 +91,13 @@ ext { uiAutomatorVersion = "2.2.0" instrumentationTestDependencies = [ - junit : "androidx.test.ext:junit:$junitInstrumentationVersion", - ktxTestCore : "androidx.test:core-ktx:$ktxTestCoreVersion", - espressoCore : "androidx.test.espresso:espresso-core:$espressoCoreVersion", - espressoContrib : "androidx.test.espresso:espresso-contrib:$espressoCoreVersion", - espressoIntents : "androidx.test.espresso:espresso-intents:$espressoIntentsVersion", - testRunner : "androidx.test:runner:$testRunnerVersion", - testRules : "androidx.test:rules:$testRulesVersion", - uiAutomator : "androidx.test.uiautomator:uiautomator:$uiAutomatorVersion", + junit : "androidx.test.ext:junit:$junitInstrumentationVersion", + ktxTestCore : "androidx.test:core-ktx:$ktxTestCoreVersion", + espressoCore : "androidx.test.espresso:espresso-core:$espressoCoreVersion", + espressoContrib: "androidx.test.espresso:espresso-contrib:$espressoCoreVersion", + espressoIntents: "androidx.test.espresso:espresso-intents:$espressoIntentsVersion", + testRunner : "androidx.test:runner:$testRunnerVersion", + testRules : "androidx.test:rules:$testRulesVersion", + uiAutomator : "androidx.test.uiautomator:uiautomator:$uiAutomatorVersion", ] } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 6dc7cb16..36c204c6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,5 +22,4 @@ org.gradle.jvmargs=-Xmx1536m # https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true - +android.enableJetifier=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a5b14cb9..8de6de4d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,12 +1,6 @@ -# -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. -# -# - -#Wed Nov 13 13:53:34 CST 2019 +#Wed Dec 09 14:22:19 EET 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip