• 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 
29 /**
30  * Plays the video by {@link MediaPlayer} on {@link TextureView}, calls {@link #create(Context, int,
31  * TextureView)} to setup the listener for TextureView and start to play the video. Once this player
32  * is no longer used, call {@link #release()} so that MediaPlayer object can be released.
33  */
34 public class VideoPlayer implements SurfaceTextureListener {
35     private final Context context;
36     private final Object mediaPlayerLock = new Object();
37     // Media player object can't be used after it has been released, so it will be set to null. But
38     // VideoPlayer is asynchronized, media player object might be paused or resumed again before
39     // released media player is set to null. Therefore, lock mediaPlayer and mediaPlayerState by
40     // mediaPlayerLock keep their states consistent.
41     @GuardedBy("mediaPlayerLock")
42     private MediaPlayer mediaPlayer;
43     @GuardedBy("mediaPlayerLock")
44     private State mediaPlayerState = State.NONE;
45     @RawRes
46     private final int videoRes;
47     private Surface animationSurface;
48 
49 
50     /**
51      * Creates a {@link MediaPlayer} for a given resource id and starts playback when the surface
52      * for
53      * a given {@link TextureView} is ready.
54      */
create(Context context, @RawRes int videoRes, TextureView textureView)55     public static VideoPlayer create(Context context, @RawRes int videoRes,
56             TextureView textureView) {
57         return new VideoPlayer(context, videoRes, textureView);
58     }
59 
VideoPlayer(Context context, @RawRes int videoRes, TextureView textureView)60     private VideoPlayer(Context context, @RawRes int videoRes, TextureView textureView) {
61         this.context = context;
62         this.videoRes = videoRes;
63         textureView.setSurfaceTextureListener(this);
64     }
65 
pause()66     public void pause() {
67         synchronized (mediaPlayerLock) {
68             if (mediaPlayerState == State.STARTED) {
69                 mediaPlayerState = State.PAUSED;
70                 mediaPlayer.pause();
71             }
72         }
73     }
74 
resume()75     public void resume() {
76         synchronized (mediaPlayerLock) {
77             if (mediaPlayerState == State.PAUSED) {
78                 mediaPlayer.start();
79                 mediaPlayerState = State.STARTED;
80             }
81         }
82     }
83 
84     /** Release media player when it's no longer needed. */
release()85     public void release() {
86         synchronized (mediaPlayerLock) {
87             if (mediaPlayerState != State.NONE && mediaPlayerState != State.END) {
88                 mediaPlayerState = State.END;
89                 mediaPlayer.release();
90                 mediaPlayer = null;
91             }
92         }
93         if (animationSurface != null) {
94             animationSurface.release();
95             animationSurface = null;
96         }
97     }
98 
99     @Override
onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)100     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
101         animationSurface = new Surface(surface);
102         synchronized (mediaPlayerLock) {
103             mediaPlayer = MediaPlayer.create(context, videoRes);
104             mediaPlayerState = State.PREPARED;
105             mediaPlayer.setSurface(animationSurface);
106             mediaPlayer.setLooping(true);
107             mediaPlayer.start();
108             mediaPlayerState = State.STARTED;
109         }
110     }
111 
112     @Override
onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)113     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
114     }
115 
116     @Override
onSurfaceTextureDestroyed(SurfaceTexture surface)117     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
118         release();
119         return false;
120     }
121 
122     @Override
onSurfaceTextureUpdated(SurfaceTexture surface)123     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
124     }
125 
126     /**
127      * The state of MediaPlayer object. Refer to
128      * https://developer.android.com/reference/android/media/MediaPlayer#StateDiagram.
129      */
130     public enum State {
131         /** MediaPlayer objects has not be created. */
132         NONE,
133         /** MediaPlayer objects is created by create() method. */
134         PREPARED,
135         /** MediaPlayer is started. It can be paused by pause() method. */
136         STARTED,
137         /** MediaPlayer object is paused. Calling start() to resume it. */
138         PAUSED,
139         /**
140          * MediaPlayer object is stopped and cannot be started until calling prepare() or
141          * prepareAsync()
142          * methods.
143          */
144         STOPPED,
145         /** MediaPlayer object is released. It cannot be used again. */
146         END
147     }
148 }
149 
150