Release IllustrationVideoView in onStop
Based on the view's visibility, release or reattach IllustrationVideoView as soon as it becomes invisible to avoid media player resources being held on for a long time, and to avoid multiple video views being released all at once at the end of setup wizard. Test: ./gradlew test connectedAndroidTest Bug: 78360819 Change-Id: Idc5af901122562d12ff3d7b1ee46012b7a60cf25
This commit is contained in:
parent
a1df48d7dc
commit
6ffb792f46
|
@ -65,6 +65,8 @@ public class IllustrationVideoView extends TextureView implements Animatable,
|
||||||
|
|
||||||
@VisibleForTesting Surface mSurface;
|
@VisibleForTesting Surface mSurface;
|
||||||
|
|
||||||
|
protected int mWindowVisibility;
|
||||||
|
|
||||||
public IllustrationVideoView(Context context, AttributeSet attrs) {
|
public IllustrationVideoView(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
final TypedArray a = context.obtainStyledAttributes(attrs,
|
final TypedArray a = context.obtainStyledAttributes(attrs,
|
||||||
|
@ -125,7 +127,7 @@ public class IllustrationVideoView extends TextureView implements Animatable,
|
||||||
* Creates a media player for the current URI. The media player will be started immediately if
|
* Creates a media player for the current URI. The media player will be started immediately if
|
||||||
* the view's window is visible. If there is an existing media player, it will be released.
|
* the view's window is visible. If there is an existing media player, it will be released.
|
||||||
*/
|
*/
|
||||||
private void createMediaPlayer() {
|
protected void createMediaPlayer() {
|
||||||
if (mMediaPlayer != null) {
|
if (mMediaPlayer != null) {
|
||||||
mMediaPlayer.release();
|
mMediaPlayer.release();
|
||||||
}
|
}
|
||||||
|
@ -150,11 +152,35 @@ public class IllustrationVideoView extends TextureView implements Animatable,
|
||||||
} else {
|
} else {
|
||||||
Log.wtf(TAG, "Unable to initialize media player for video view");
|
Log.wtf(TAG, "Unable to initialize media player for video view");
|
||||||
}
|
}
|
||||||
if (getWindowVisibility() == View.VISIBLE) {
|
if (mWindowVisibility == View.VISIBLE) {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void createSurface() {
|
||||||
|
if (mSurface != null) {
|
||||||
|
mSurface.release();
|
||||||
|
mSurface = null;
|
||||||
|
}
|
||||||
|
// Reattach only if it has been previously released
|
||||||
|
SurfaceTexture surfaceTexture = getSurfaceTexture();
|
||||||
|
if (surfaceTexture != null) {
|
||||||
|
setVisibility(View.INVISIBLE);
|
||||||
|
mSurface = new Surface(surfaceTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onWindowVisibilityChanged(int visibility) {
|
||||||
|
super.onWindowVisibilityChanged(visibility);
|
||||||
|
mWindowVisibility = visibility;
|
||||||
|
if (visibility == View.VISIBLE) {
|
||||||
|
reattach();
|
||||||
|
} else {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the media player should play the video in a continuous loop. The default value is
|
* Whether the media player should play the video in a continuous loop. The default value is
|
||||||
* true.
|
* true.
|
||||||
|
@ -179,14 +205,34 @@ public class IllustrationVideoView extends TextureView implements Animatable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reattach() {
|
||||||
|
if (mSurface == null) {
|
||||||
|
initVideo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initVideo() {
|
||||||
|
if (mWindowVisibility != View.VISIBLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
createSurface();
|
||||||
|
if (mSurface != null) {
|
||||||
|
createMediaPlayer();
|
||||||
|
} else {
|
||||||
|
Log.w("IllustrationVideoView", "Surface creation failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onRenderingStart() {
|
||||||
|
}
|
||||||
|
|
||||||
/* SurfaceTextureListener methods */
|
/* SurfaceTextureListener methods */
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
|
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
|
||||||
// Keep the view hidden until video starts
|
// Keep the view hidden until video starts
|
||||||
setVisibility(View.INVISIBLE);
|
setVisibility(View.INVISIBLE);
|
||||||
mSurface = new Surface(surfaceTexture);
|
initVideo();
|
||||||
createMediaPlayer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -231,6 +277,7 @@ public class IllustrationVideoView extends TextureView implements Animatable,
|
||||||
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
|
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
|
||||||
// Video available, show view now
|
// Video available, show view now
|
||||||
setVisibility(View.VISIBLE);
|
setVisibility(View.VISIBLE);
|
||||||
|
onRenderingStart();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package com.android.setupwizardlib.view;
|
package com.android.setupwizardlib.view;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
@ -30,6 +32,7 @@ import android.graphics.SurfaceTexture;
|
||||||
import android.media.MediaPlayer;
|
import android.media.MediaPlayer;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.RawRes;
|
import androidx.annotation.RawRes;
|
||||||
|
|
||||||
|
@ -91,6 +94,30 @@ public class IllustrationVideoViewTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onVisibilityChanged_notVisible_shouldRelease() {
|
||||||
|
createDefaultView();
|
||||||
|
mView.onWindowVisibilityChanged(View.GONE);
|
||||||
|
|
||||||
|
verify(ShadowMockMediaPlayer.sMediaPlayer).release();
|
||||||
|
assertThat(mView.mSurface).isNull();
|
||||||
|
assertThat(mView.mMediaPlayer).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onVisibilityChanged_visible_shouldPlay() {
|
||||||
|
createDefaultView();
|
||||||
|
|
||||||
|
mView.onWindowVisibilityChanged(View.GONE);
|
||||||
|
assertThat(mView.mSurface).isNull();
|
||||||
|
assertThat(mView.mMediaPlayer).isNull();
|
||||||
|
|
||||||
|
mView.onWindowVisibilityChanged(View.VISIBLE);
|
||||||
|
|
||||||
|
assertThat(mView.mSurface).isNotNull();
|
||||||
|
assertThat(mView.mMediaPlayer).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPausedWhenWindowFocusLost() {
|
public void testPausedWhenWindowFocusLost() {
|
||||||
createDefaultView();
|
createDefaultView();
|
||||||
|
@ -149,6 +176,7 @@ public class IllustrationVideoViewTest {
|
||||||
// Any resource attribute should work, since the media player is mocked
|
// Any resource attribute should work, since the media player is mocked
|
||||||
.addAttribute(R.attr.suwVideo, "@android:color/white")
|
.addAttribute(R.attr.suwVideo, "@android:color/white")
|
||||||
.build());
|
.build());
|
||||||
|
mView.setSurfaceTexture(mock(SurfaceTexture.class));
|
||||||
mView.onSurfaceTextureAvailable(mSurfaceTexture, 500, 500);
|
mView.onSurfaceTextureAvailable(mSurfaceTexture, 500, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue