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