| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.example.android.pictureinpicture |
| |
| import android.content.pm.ActivityInfo |
| import android.support.test.InstrumentationRegistry |
| import android.support.test.espresso.Espresso.onView |
| import android.support.test.espresso.UiController |
| import android.support.test.espresso.ViewAction |
| import android.support.test.espresso.action.ViewActions.click |
| import android.support.test.espresso.assertion.ViewAssertions.matches |
| import android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom |
| import android.support.test.espresso.matcher.ViewMatchers.isDisplayed |
| import android.support.test.espresso.matcher.ViewMatchers.withId |
| import android.support.test.rule.ActivityTestRule |
| import android.support.test.runner.AndroidJUnit4 |
| import android.support.v4.media.session.PlaybackStateCompat |
| import android.view.View |
| import com.example.android.pictureinpicture.widget.MovieView |
| import org.hamcrest.Description |
| import org.hamcrest.Matcher |
| import org.hamcrest.Matchers.not |
| import org.hamcrest.TypeSafeMatcher |
| import org.hamcrest.core.AllOf.allOf |
| import org.hamcrest.core.Is.`is` |
| import org.hamcrest.core.IsEqual.equalTo |
| import org.junit.Assert.assertNotNull |
| import org.junit.Assert.assertThat |
| import org.junit.Assert.assertTrue |
| import org.junit.Rule |
| import org.junit.Test |
| import org.junit.runner.RunWith |
| |
| |
| @RunWith(AndroidJUnit4::class) |
| class MediaSessionPlaybackActivityTest { |
| |
| @Rule @JvmField |
| val rule = ActivityTestRule(MediaSessionPlaybackActivity::class.java) |
| |
| @Test |
| fun movie_playingOnPip() { |
| // The movie should be playing on start |
| onView(withId(R.id.movie)) |
| .check(matches(allOf(isDisplayed(), isPlaying()))) |
| .perform(showControls()) |
| // Click on the button to enter Picture-in-Picture mode |
| onView(withId(R.id.minimize)).perform(click()) |
| InstrumentationRegistry.getInstrumentation().waitForIdleSync() |
| // The Activity is paused. We cannot use Espresso to test paused activities. |
| rule.runOnUiThread { |
| // We are now in Picture-in-Picture mode |
| assertTrue(rule.activity.isInPictureInPictureMode) |
| val view = rule.activity.findViewById<MovieView>(R.id.movie) |
| assertNotNull(view) |
| // The video should still be playing |
| assertTrue(view.isPlaying) |
| |
| // The media session state should be playing. |
| assertMediaStateIs(PlaybackStateCompat.STATE_PLAYING) |
| } |
| } |
| |
| @Test |
| fun movie_pauseAndResume() { |
| // The movie should be playing on start |
| onView(withId(R.id.movie)) |
| .check(matches(allOf(isDisplayed(), isPlaying()))) |
| .perform(showControls()) |
| // Pause |
| onView(withId(R.id.toggle)).perform(click()) |
| onView(withId(R.id.movie)).check(matches(not(isPlaying()))) |
| // The media session state should be paused. |
| assertMediaStateIs(PlaybackStateCompat.STATE_PAUSED) |
| // Resume |
| onView(withId(R.id.toggle)).perform(click()) |
| onView(withId(R.id.movie)).check(matches(isPlaying())) |
| // The media session state should be playing. |
| assertMediaStateIs(PlaybackStateCompat.STATE_PLAYING) |
| } |
| |
| @Test |
| fun fullscreen_enabledOnLandscape() { |
| rule.runOnUiThread { rule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE } |
| InstrumentationRegistry.getInstrumentation().waitForIdleSync() |
| rule.runOnUiThread { |
| val decorView = rule.activity.window.decorView |
| assertThat(decorView.systemUiVisibility, |
| hasFlag(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)) |
| } |
| } |
| |
| @Test |
| fun fullscreen_disabledOnPortrait() { |
| rule.runOnUiThread { |
| rule.activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT |
| } |
| InstrumentationRegistry.getInstrumentation().waitForIdleSync() |
| rule.runOnUiThread { |
| val decorView = rule.activity.window.decorView |
| assertThat(decorView.systemUiVisibility, |
| not(hasFlag(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN))) |
| } |
| } |
| |
| private fun assertMediaStateIs(@PlaybackStateCompat.State expectedState: Int) { |
| val state = rule.activity.mediaController.playbackState |
| assertNotNull(state) |
| assertThat( |
| "MediaSession is not in the correct state", |
| state?.state, |
| `is`<Int>(equalTo<Int>(expectedState))) |
| } |
| |
| private fun isPlaying(): Matcher<View> { |
| return object : TypeSafeMatcher<View>() { |
| override fun matchesSafely(view: View): Boolean { |
| return (view as MovieView).isPlaying |
| } |
| |
| override fun describeTo(description: Description) { |
| description.appendText("MovieView is playing") |
| } |
| } |
| } |
| |
| private fun showControls(): ViewAction { |
| return object : ViewAction { |
| override fun getConstraints(): Matcher<View> { |
| return isAssignableFrom(MovieView::class.java) |
| } |
| |
| override fun getDescription(): String { |
| return "Show controls of MovieView" |
| } |
| |
| override fun perform(uiController: UiController, view: View) { |
| uiController.loopMainThreadUntilIdle() |
| (view as MovieView).showControls() |
| uiController.loopMainThreadUntilIdle() |
| } |
| } |
| } |
| |
| private fun hasFlag(flag: Int): Matcher<in Int> { |
| return object : TypeSafeMatcher<Int>() { |
| override fun matchesSafely(i: Int?): Boolean { |
| return i?.and(flag) == flag |
| } |
| |
| override fun describeTo(description: Description) { |
| description.appendText("Flag integer contains " + flag) |
| } |
| } |
| } |
| |
| } |