• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.settings.accessibility;
18 
19 import android.content.Context;
20 import android.graphics.SurfaceTexture;
21 import android.media.MediaPlayer;
22 import android.view.Surface;
23 import android.view.TextureView;
24 import android.view.TextureView.SurfaceTextureListener;
25 
26 import androidx.annotation.GuardedBy;
27 import androidx.annotation.RawRes;
28 import androidx.annotation.VisibleForTesting;
29 
30 /**
31  * Plays the video by {@link MediaPlayer} on {@link TextureView}, calls {@link #create(Context, int,
32  * TextureView)} to setup the listener for TextureView and start to play the video. Once this player
33  * is no longer used, call {@link #release()} so that MediaPlayer object can be released.
34  */
35 public class VideoPlayer implements SurfaceTextureListener {
36     private final Context mContext;
37     private final Object mMediaPlayerLock = new Object();
38     // Media player object can't be used after it has been released, so it will be set to null. But
39     // VideoPlayer is asynchronized, media player object might be paused or resumed again before
40     // released media player is set to null. Therefore, lock mediaPlayer and mediaPlayerState by
41     // mediaPlayerLock keep their states consistent.
42     @VisibleForTesting
43     @GuardedBy("mediaPlayerLock")
44     MediaPlayer mMediaPlayer;
45 
46     @VisibleForTesting
47     @GuardedBy("mediaPlayerLock")
48     State mMediaPlayerState = State.NONE;
49 
50     @RawRes
51     private final int mVideoRes;
52 
53     @VisibleForTesting
54     Surface mAnimationSurface;
55 
56 
57     /**
58      * Creates a {@link MediaPlayer} for a given resource id and starts playback when the surface
59      * for
60      * a given {@link TextureView} is ready.
61      */
create(Context context, @RawRes int videoRes, TextureView textureView)62     public static VideoPlayer create(Context context, @RawRes int videoRes,
63             TextureView textureView) {
64         return new VideoPlayer(context, videoRes, textureView);
65     }
66 
VideoPlayer(Context context, @RawRes int videoRes, TextureView textureView)67     private VideoPlayer(Context context, @RawRes int videoRes, TextureView textureView) {
68         this.mContext = context;
69         this.mVideoRes = videoRes;
70         textureView.setSurfaceTextureListener(this);
71     }
72 
pause()73     public void pause() {
74         synchronized (mMediaPlayerLock) {
75             if (mMediaPlayerState == State.STARTED) {
76                 mMediaPlayerState = State.PAUSED;
77                 mMediaPlayer.pause();
78             }
79         }
80     }
81 
resume()82     public void resume() {
83         synchronized (mMediaPlayerLock) {
84             if (mMediaPlayerState == State.PAUSED) {
85                 mMediaPlayer.start();
86                 mMediaPlayerState = State.STARTED;
87             }
88         }
89     }
90 
91     /** Release media player when it's no longer needed. */
release()92     public void release() {
93         synchronized (mMediaPlayerLock) {
94             if (mMediaPlayerState != State.NONE && mMediaPlayerState != State.END) {
95                 mMediaPlayerState = State.END;
96                 mMediaPlayer.release();
97                 mMediaPlayer = null;
98             }
99         }
100         if (mAnimationSurface != null) {
101             mAnimationSurface.release();
102             mAnimationSurface = null;
103         }
104     }
105 
106     @Override
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)107     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
108         mAnimationSurface = new Surface(surface);
109         synchronized (mMediaPlayerLock) {
110             mMediaPlayer = MediaPlayer.create(mContext, mVideoRes);
111             mMediaPlayerState = State.PREPARED;
112             mMediaPlayer.setSurface(mAnimationSurface);
113             mMediaPlayer.setLooping(true);
114             mMediaPlayer.start();
115             mMediaPlayerState = State.STARTED;
116         }
117     }
118 
119     @Override
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)120     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
121     }
122 
123     @Override
onSurfaceTextureDestroyed(SurfaceTexture surface)124     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
125         release();
126         return false;
127     }
128 
129     @Override
onSurfaceTextureUpdated(SurfaceTexture surface)130     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
131     }
132 
133     /**
134      * The state of MediaPlayer object. Refer to
135      * https://developer.android.com/reference/android/media/MediaPlayer#StateDiagram.
136      */
137     public enum State {
138         /** MediaPlayer objects has not be created. */
139         NONE,
140         /** MediaPlayer objects is created by create() method. */
141         PREPARED,
142         /** MediaPlayer is started. It can be paused by pause() method. */
143         STARTED,
144         /** MediaPlayer object is paused. Calling start() to resume it. */
145         PAUSED,
146         /**
147          * MediaPlayer object is stopped and cannot be started until calling prepare() or
148          * prepareAsync()
149          * methods.
150          */
151         STOPPED,
152         /** MediaPlayer object is released. It cannot be used again. */
153         END
154     }
155 }
156 
157