Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit febcf52a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Rename and add test cases for video player in accessibility."

parents 2e78fd71 5bd435e6
Loading
Loading
Loading
Loading
+39 −32
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.view.TextureView.SurfaceTextureListener;

import androidx.annotation.GuardedBy;
import androidx.annotation.RawRes;
import androidx.annotation.VisibleForTesting;

/**
 * Plays the video by {@link MediaPlayer} on {@link TextureView}, calls {@link #create(Context, int,
@@ -32,19 +33,25 @@ import androidx.annotation.RawRes;
 * is no longer used, call {@link #release()} so that MediaPlayer object can be released.
 */
public class VideoPlayer implements SurfaceTextureListener {
    private final Context context;
    private final Object mediaPlayerLock = new Object();
    private final Context mContext;
    private final Object mMediaPlayerLock = new Object();
    // Media player object can't be used after it has been released, so it will be set to null. But
    // VideoPlayer is asynchronized, media player object might be paused or resumed again before
    // released media player is set to null. Therefore, lock mediaPlayer and mediaPlayerState by
    // mediaPlayerLock keep their states consistent.
    @VisibleForTesting
    @GuardedBy("mediaPlayerLock")
    private MediaPlayer mediaPlayer;
    MediaPlayer mMediaPlayer;

    @VisibleForTesting
    @GuardedBy("mediaPlayerLock")
    private State mediaPlayerState = State.NONE;
    State mMediaPlayerState = State.NONE;

    @RawRes
    private final int videoRes;
    private Surface animationSurface;
    private final int mVideoRes;

    @VisibleForTesting
    Surface mAnimationSurface;


    /**
@@ -58,54 +65,54 @@ public class VideoPlayer implements SurfaceTextureListener {
    }

    private VideoPlayer(Context context, @RawRes int videoRes, TextureView textureView) {
        this.context = context;
        this.videoRes = videoRes;
        this.mContext = context;
        this.mVideoRes = videoRes;
        textureView.setSurfaceTextureListener(this);
    }

    public void pause() {
        synchronized (mediaPlayerLock) {
            if (mediaPlayerState == State.STARTED) {
                mediaPlayerState = State.PAUSED;
                mediaPlayer.pause();
        synchronized (mMediaPlayerLock) {
            if (mMediaPlayerState == State.STARTED) {
                mMediaPlayerState = State.PAUSED;
                mMediaPlayer.pause();
            }
        }
    }

    public void resume() {
        synchronized (mediaPlayerLock) {
            if (mediaPlayerState == State.PAUSED) {
                mediaPlayer.start();
                mediaPlayerState = State.STARTED;
        synchronized (mMediaPlayerLock) {
            if (mMediaPlayerState == State.PAUSED) {
                mMediaPlayer.start();
                mMediaPlayerState = State.STARTED;
            }
        }
    }

    /** Release media player when it's no longer needed. */
    public void release() {
        synchronized (mediaPlayerLock) {
            if (mediaPlayerState != State.NONE && mediaPlayerState != State.END) {
                mediaPlayerState = State.END;
                mediaPlayer.release();
                mediaPlayer = null;
        synchronized (mMediaPlayerLock) {
            if (mMediaPlayerState != State.NONE && mMediaPlayerState != State.END) {
                mMediaPlayerState = State.END;
                mMediaPlayer.release();
                mMediaPlayer = null;
            }
        }
        if (animationSurface != null) {
            animationSurface.release();
            animationSurface = null;
        if (mAnimationSurface != null) {
            mAnimationSurface.release();
            mAnimationSurface = null;
        }
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        animationSurface = new Surface(surface);
        synchronized (mediaPlayerLock) {
            mediaPlayer = MediaPlayer.create(context, videoRes);
            mediaPlayerState = State.PREPARED;
            mediaPlayer.setSurface(animationSurface);
            mediaPlayer.setLooping(true);
            mediaPlayer.start();
            mediaPlayerState = State.STARTED;
        mAnimationSurface = new Surface(surface);
        synchronized (mMediaPlayerLock) {
            mMediaPlayer = MediaPlayer.create(mContext, mVideoRes);
            mMediaPlayerState = State.PREPARED;
            mMediaPlayer.setSurface(mAnimationSurface);
            mMediaPlayer.setLooping(true);
            mMediaPlayer.start();
            mMediaPlayerState = State.STARTED;
        }
    }

+114 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.android.settings.accessibility;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.media.MediaPlayer;
import android.view.Surface;
import android.view.TextureView;

import androidx.test.core.app.ApplicationProvider;

import com.android.settings.accessibility.VideoPlayer.State;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;

/** Tests for {@link VideoPlayer}. */
@RunWith(RobolectricTestRunner.class)
public class VideoPlayerTest {

    @Mock
    private MediaPlayer mMediaPlayer;

    @Mock
    private TextureView mTextureView;

    @Mock
    private Surface mSurface;

    private VideoPlayer mVideoPlayer;

    @Before
    public void initVideoPlayer() {
        MockitoAnnotations.initMocks(this);

        final int videoRes = 0;
        final Context context = ApplicationProvider.getApplicationContext();

        mVideoPlayer = spy(VideoPlayer.create(context, videoRes, mTextureView));
        mVideoPlayer.mMediaPlayer = mMediaPlayer;
        mVideoPlayer.mAnimationSurface = mSurface;
    }

    @Test
    public void setSurfaceTextureListener_success() {
        verify(mTextureView).setSurfaceTextureListener(any());
    }

    @Test
    public void onPlayerPaused_startedState_pause() {
        mVideoPlayer.mMediaPlayerState = State.STARTED;

        mVideoPlayer.pause();

        assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.PAUSED);
        verify(mMediaPlayer).pause();
    }

    @Test
    public void onPlayerResumed_pausedState_start() {
        mVideoPlayer.mMediaPlayerState = State.PAUSED;

        mVideoPlayer.resume();

        assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.STARTED);
        verify(mMediaPlayer).start();
    }

    @Test
    public void onPlayerReleased_stoppedState_release() {
        mVideoPlayer.mMediaPlayerState = State.STOPPED;

        mVideoPlayer.release();

        assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.END);
        verify(mMediaPlayer).release();
        verify(mSurface).release();
    }

    @Test
    public void onSurfaceTextureDestroyed_preparedState_release() {
        mVideoPlayer.mMediaPlayerState = State.PREPARED;

        mVideoPlayer.onSurfaceTextureDestroyed(any());

        assertThat(mVideoPlayer.mMediaPlayerState).isEqualTo(State.END);
        verify(mMediaPlayer).release();
        verify(mSurface).release();
    }
}