1 package expo.modules.av.video;
2 
3 import android.annotation.SuppressLint;
4 import android.content.Context;
5 import android.graphics.Matrix;
6 import android.graphics.SurfaceTexture;
7 import android.util.Pair;
8 import android.util.Size;
9 import android.view.Surface;
10 import android.view.TextureView;
11 import android.view.View;
12 
13 import expo.modules.av.video.scalablevideoview.ScalableType;
14 import expo.modules.av.video.scalablevideoview.ScaleManager;
15 
16 @SuppressLint("ViewConstructor")
17 public class VideoTextureView extends TextureView implements TextureView.SurfaceTextureListener {
18 
19   private VideoView mVideoView = null;
20   private boolean mIsAttachedToWindow = false;
21   private Surface mSurface = null;
22   private boolean mVisible = true;
23 
VideoTextureView(final Context themedReactContext, VideoView videoView)24   public VideoTextureView(final Context themedReactContext, VideoView videoView) {
25     super(themedReactContext, null, 0);
26 
27     mVideoView = videoView;
28 
29     setSurfaceTextureListener(this);
30   }
31 
isAttachedToWindow()32   public boolean isAttachedToWindow() {
33     return mIsAttachedToWindow;
34   }
35 
getSurface()36   public Surface getSurface() {
37     return mSurface;
38   }
39 
scaleVideoSize(final Pair<Integer, Integer> videoWidthHeight, ScalableType resizeMode)40   public void scaleVideoSize(final Pair<Integer, Integer> videoWidthHeight, ScalableType resizeMode) {
41     final int videoWidth = videoWidthHeight.first;
42     final int videoHeight = videoWidthHeight.second;
43 
44     if (videoWidth == 0 || videoHeight == 0) {
45       return;
46     }
47 
48     final Size viewSize = new Size(getWidth(), getHeight());
49     final Size videoSize = new Size(videoWidth, videoHeight);
50     final Matrix matrix = new ScaleManager(viewSize, videoSize).getScaleMatrix(resizeMode);
51     if (matrix != null) {
52       Matrix prevMatrix = new Matrix();
53       getTransform(prevMatrix);
54       if (!matrix.equals(prevMatrix)) {
55         setTransform(matrix);
56         invalidate();
57       }
58     }
59   }
60 
onResume()61   public void onResume() {
62 
63     // TextureView contains a bug which sometimes causes the view to
64     // not be rendered after resuming the app (e.g. by unlocking the screen).
65     // The bug occurs when the hardware layer is destroyed, but onVisibilityChanged
66     // has not been called. For this particular case we forcefully invalidate the
67     // view and its layer so it is always drawn correctly after resuming.
68     if (mVisible) {
69       onVisibilityChanged(this, View.INVISIBLE);
70       onVisibilityChanged(this, View.VISIBLE);
71     }
72   }
73 
74   // TextureView
75 
76   @Override
onSurfaceTextureAvailable(final SurfaceTexture surfaceTexture, final int width, final int height)77   public void onSurfaceTextureAvailable(final SurfaceTexture surfaceTexture, final int width, final int height) {
78     mSurface = new Surface(surfaceTexture);
79     mVideoView.tryUpdateVideoSurface(mSurface);
80   }
81 
82   @Override
onSurfaceTextureSizeChanged(final SurfaceTexture surfaceTexture, final int width, final int height)83   public void onSurfaceTextureSizeChanged(final SurfaceTexture surfaceTexture, final int width, final int height) {
84     // no-op
85   }
86 
87   @Override
onSurfaceTextureUpdated(final SurfaceTexture surfaceTexture)88   public void onSurfaceTextureUpdated(final SurfaceTexture surfaceTexture) {
89     // no-op
90   }
91 
92   @Override
onSurfaceTextureDestroyed(final SurfaceTexture surfaceTexture)93   public boolean onSurfaceTextureDestroyed(final SurfaceTexture surfaceTexture) {
94     mSurface = null;
95     mVideoView.tryUpdateVideoSurface(null);
96     return true;
97   }
98 
99   // View
100 
101   @Override
onDetachedFromWindow()102   protected void onDetachedFromWindow() {
103     super.onDetachedFromWindow();
104     mIsAttachedToWindow = false;
105   }
106 
107   @Override
onAttachedToWindow()108   protected void onAttachedToWindow() {
109     super.onAttachedToWindow();
110     mIsAttachedToWindow = true;
111     mVideoView.tryUpdateVideoSurface(mSurface);
112   }
113 
onVisibilityChanged(View changedView, int visibility)114   protected void onVisibilityChanged(View changedView, int visibility) {
115     super.onVisibilityChanged(changedView, visibility);
116     mVisible = visibility == View.VISIBLE;
117   }
118 }
119