Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added integration for Photo Editor app with new screen manager SDK #48

Merged
merged 4 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions PhotoEditor/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*
*/

apply plugin: 'com.android.application'
Expand Down Expand Up @@ -33,14 +32,16 @@ android {
}

dependencies {
implementation microsoftDependencies.screenManager
implementation microsoftDependencies.layouts
implementation microsoftDependencies.fragmentsHandler

implementation kotlinDependencies.kotlinStdlib
implementation androidxDependencies.appCompat
implementation androidxDependencies.constraintLayout
implementation androidxDependencies.ktxCore
implementation androidxDependencies.ktxFragment

implementation microsoftDependencies.dualScreenLayout

testImplementation testDependencies.junit
androidTestImplementation instrumentationTestDependencies.junit
androidTestImplementation instrumentationTestDependencies.espressoCore
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

package com.microsoft.device.display.samples.photoeditor

import android.content.Intent
Expand All @@ -18,8 +23,12 @@ import androidx.test.rule.ActivityTestRule
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import com.microsoft.device.dualscreen.layout.ScreenHelper
import com.microsoft.device.display.samples.photoeditor.utils.ScreenInfoListenerImpl
import com.microsoft.device.dualscreen.ScreenManagerProvider
import org.hamcrest.CoreMatchers.not
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
Expand All @@ -34,6 +43,21 @@ import org.hamcrest.CoreMatchers.`is` as iz
class PhotoEditorUITest {
@get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java)
private var screenInfoListener = ScreenInfoListenerImpl()

@Before
fun setup() {
val screenManager = ScreenManagerProvider.getScreenManager()
screenManager.addScreenInfoListener(screenInfoListener)
}

@After
fun tearDown() {
val screenManager = ScreenManagerProvider.getScreenManager()
screenManager.removeScreenInfoListener(screenInfoListener)
screenInfoListener.resetScreenInfo()
screenInfoListener.resetScreenInfoCounter()
}

/**
* Tests visibility of controls when app spanned vs. unspanned
Expand All @@ -53,7 +77,7 @@ class PhotoEditorUITest {
onView(withId(R.id.warmth)).check(matches(withEffectiveVisibility(Visibility.INVISIBLE)))

spanFromLeft()
assertThat(isSpanned(), iz(true))
waitForScreenInfoAndAssert { Assert.assertTrue(isSpanned()) }

// Switched to dual-screen mode, so dropdown should not exist and all sliders should be visible
onView(withId(R.id.controls)).check(doesNotExist())
Expand Down Expand Up @@ -100,7 +124,10 @@ class PhotoEditorUITest {
device.wait(Until.hasObject(By.pkg(filesPackage).depth(0)), 3000) // timeout at 3 seconds

// Before import, drawable is equal to prev
assertThat(prev, iz(activityRule.activity.findViewById<ImageFilterView>(R.id.image).drawable))
assertThat(
prev,
iz(activityRule.activity.findViewById<ImageFilterView>(R.id.image).drawable)
)

// Hardcoded to select most recently saved file in Files app - must be an image file
device.swipe(1550, 1230, 1550, 1230, 100)
Expand Down Expand Up @@ -207,8 +234,13 @@ class PhotoEditorUITest {
device.swipe(rightX, bottomY, rightX, middleY, closeSteps)
}

private fun waitForScreenInfoAndAssert(assert: () -> Unit) {
screenInfoListener.waitForScreenInfoChanges()
assert()
screenInfoListener.resetScreenInfo()
}

private fun isSpanned(): Boolean {
onIdle() // wait until layout changes have been fully processed before checking
return ScreenHelper.isDualMode(activityRule.activity)
return screenInfoListener.screenInfo?.isDualMode() == true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

package com.microsoft.device.display.samples.photoeditor.utils

import com.microsoft.device.dualscreen.ScreenInfo
import com.microsoft.device.dualscreen.ScreenInfoListener
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

/**
* Simple implementation for [ScreenInfoListener] that saves internally the last screen info data.
*/
class ScreenInfoListenerImpl : ScreenInfoListener {
private var _screenInfo: ScreenInfo? = null
val screenInfo: ScreenInfo?
get() = _screenInfo
private var screenInfoLatch: CountDownLatch? = null

override fun onScreenInfoChanged(screenInfo: ScreenInfo) {
_screenInfo = screenInfo
screenInfoLatch?.countDown()
}

/**
* Resets the last screen info to [null]
*/
fun resetScreenInfo() {
_screenInfo = null
}

/**
* Resets screen info counter when waiting for a screen changes to happen before calling
* [waitForScreenInfoChanges].
*/
fun resetScreenInfoCounter() {
screenInfoLatch = CountDownLatch(1)
}

/**
* Blocks and waits for the next screen info changes to happen.
* @return {@code true} if the screen info changed before the timeout count reached zero and
* {@code false} if the waiting time elapsed before the changes happened.
*/
fun waitForScreenInfoChanges(): Boolean {
return try {
val result = screenInfoLatch?.await(10, TimeUnit.SECONDS) ?: false
result
} catch (e: InterruptedException) {
false
}
}
}
2 changes: 1 addition & 1 deletion PhotoEditor/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) Microsoft Corporation. All rights reserved.
~ Licensed under the MIT License.
~
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.microsoft.device.display.samples.photoeditor">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".PhotoEditorApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

package com.microsoft.device.display.samples.photoeditor

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer

fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
class RemovableObserver : Observer<T> {
override fun onChanged(t: T?) {
observer.onChanged(t)
removeObserver(this)
}
}

observe(lifecycleOwner, RemovableObserver())
}
Loading