diff options
Diffstat (limited to 'java/com/android/incallui/videosurface/impl/VideoSurfaceTextureImpl.java')
-rw-r--r-- | java/com/android/incallui/videosurface/impl/VideoSurfaceTextureImpl.java | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/java/com/android/incallui/videosurface/impl/VideoSurfaceTextureImpl.java b/java/com/android/incallui/videosurface/impl/VideoSurfaceTextureImpl.java new file mode 100644 index 000000000..21160cadb --- /dev/null +++ b/java/com/android/incallui/videosurface/impl/VideoSurfaceTextureImpl.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.incallui.videosurface.impl; + +import android.graphics.Point; +import android.graphics.SurfaceTexture; +import android.view.Surface; +import android.view.TextureView; +import android.view.View; +import com.android.dialer.common.LogUtil; +import com.android.incallui.videosurface.protocol.VideoSurfaceDelegate; +import com.android.incallui.videosurface.protocol.VideoSurfaceTexture; +import java.util.Locale; +import java.util.Objects; + +/** + * Represents a {@link TextureView} and its associated {@link SurfaceTexture} and {@link Surface}. + * Used to manage the lifecycle of these objects across device orientation changes. + */ +public class VideoSurfaceTextureImpl implements VideoSurfaceTexture { + @SurfaceType private final int surfaceType; + private VideoSurfaceDelegate delegate; + private TextureView textureView; + private Surface savedSurface; + private SurfaceTexture savedSurfaceTexture; + private Point surfaceDimensions; + private Point sourceVideoDimensions; + private boolean isDoneWithSurface; + + public VideoSurfaceTextureImpl(@SurfaceType int surfaceType) { + this.surfaceType = surfaceType; + } + + @Override + public void setDelegate(VideoSurfaceDelegate delegate) { + LogUtil.i("VideoSurfaceTextureImpl.setDelegate", "delegate: " + delegate + " " + toString()); + this.delegate = delegate; + } + + @Override + public int getSurfaceType() { + return surfaceType; + } + + @Override + public Surface getSavedSurface() { + return savedSurface; + } + + @Override + public void setSurfaceDimensions(Point surfaceDimensions) { + LogUtil.i( + "VideoSurfaceTextureImpl.setSurfaceDimensions", + "surfaceDimensions: " + surfaceDimensions + " " + toString()); + this.surfaceDimensions = surfaceDimensions; + if (surfaceDimensions != null && savedSurfaceTexture != null) { + savedSurfaceTexture.setDefaultBufferSize(surfaceDimensions.x, surfaceDimensions.y); + } + } + + @Override + public Point getSurfaceDimensions() { + return surfaceDimensions; + } + + @Override + public void setSourceVideoDimensions(Point sourceVideoDimensions) { + this.sourceVideoDimensions = sourceVideoDimensions; + } + + @Override + public Point getSourceVideoDimensions() { + return sourceVideoDimensions; + } + + @Override + public void attachToTextureView(TextureView textureView) { + if (this.textureView == textureView) { + return; + } + LogUtil.i("VideoSurfaceTextureImpl.attachToTextureView", toString()); + + if (this.textureView != null) { + this.textureView.setOnClickListener(null); + // Don't clear the surface texture listener. This is important because our listener prevents + // the surface from being released so that it can be reused later. + } + + this.textureView = textureView; + textureView.setSurfaceTextureListener(new SurfaceTextureListener()); + textureView.setOnClickListener(new OnClickListener()); + + boolean areSameSurfaces = Objects.equals(savedSurfaceTexture, textureView.getSurfaceTexture()); + LogUtil.i("VideoSurfaceTextureImpl.attachToTextureView", "areSameSurfaces: " + areSameSurfaces); + if (savedSurfaceTexture != null && !areSameSurfaces) { + textureView.setSurfaceTexture(savedSurfaceTexture); + if (surfaceDimensions != null && createSurface(surfaceDimensions.x, surfaceDimensions.y)) { + onSurfaceCreated(); + } + } + isDoneWithSurface = false; + } + + @Override + public void setDoneWithSurface() { + LogUtil.i("VideoSurfaceTextureImpl.setDoneWithSurface", toString()); + isDoneWithSurface = true; + if (textureView != null && textureView.isAvailable()) { + return; + } + if (savedSurface != null) { + onSurfaceReleased(); + savedSurface.release(); + savedSurface = null; + } + if (savedSurfaceTexture != null) { + savedSurfaceTexture.release(); + savedSurfaceTexture = null; + } + } + + private boolean createSurface(int width, int height) { + LogUtil.i( + "VideoSurfaceTextureImpl.createSurface", + "width: " + width + ", height: " + height + " " + toString()); + if (savedSurfaceTexture != null) { + savedSurfaceTexture.setDefaultBufferSize(width, height); + savedSurface = new Surface(savedSurfaceTexture); + return true; + } + return false; + } + + private void onSurfaceCreated() { + if (delegate != null) { + delegate.onSurfaceCreated(this); + } else { + LogUtil.e("VideoSurfaceTextureImpl.onSurfaceCreated", "delegate is null. " + toString()); + } + } + + private void onSurfaceReleased() { + if (delegate != null) { + delegate.onSurfaceReleased(this); + } else { + LogUtil.e("VideoSurfaceTextureImpl.onSurfaceReleased", "delegate is null. " + toString()); + } + } + + @Override + public String toString() { + return String.format( + Locale.US, + "VideoSurfaceTextureImpl<%s%s%s%s>", + (surfaceType == SURFACE_TYPE_LOCAL ? "local, " : "remote, "), + (savedSurface == null ? "no-surface, " : ""), + (savedSurfaceTexture == null ? "no-texture, " : ""), + (surfaceDimensions == null + ? "(-1 x -1)" + : (surfaceDimensions.x + " x " + surfaceDimensions.y))); + } + + private class SurfaceTextureListener implements TextureView.SurfaceTextureListener { + @Override + public void onSurfaceTextureAvailable(SurfaceTexture newSurfaceTexture, int width, int height) { + LogUtil.i( + "SurfaceTextureListener.onSurfaceTextureAvailable", + "newSurfaceTexture: " + + newSurfaceTexture + + " " + + VideoSurfaceTextureImpl.this.toString()); + + // Where there is no saved {@link SurfaceTexture} available, use the newly created one. + // If a saved {@link SurfaceTexture} is available, we are re-creating after an + // orientation change. + boolean surfaceCreated; + if (savedSurfaceTexture == null) { + savedSurfaceTexture = newSurfaceTexture; + surfaceCreated = createSurface(width, height); + } else { + // A saved SurfaceTexture was found. + LogUtil.i( + "SurfaceTextureListener.onSurfaceTextureAvailable", "replacing with cached surface..."); + textureView.setSurfaceTexture(savedSurfaceTexture); + surfaceCreated = true; + } + + // Inform the delegate that the surface is available. + if (surfaceCreated) { + onSurfaceCreated(); + } + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture destroyedSurfaceTexture) { + LogUtil.i( + "SurfaceTextureListener.onSurfaceTextureDestroyed", + "destroyedSurfaceTexture: " + + destroyedSurfaceTexture + + " " + + VideoSurfaceTextureImpl.this.toString()); + if (delegate != null) { + delegate.onSurfaceDestroyed(VideoSurfaceTextureImpl.this); + } else { + LogUtil.e("SurfaceTextureListener.onSurfaceTextureDestroyed", "delegate is null"); + } + + if (isDoneWithSurface) { + onSurfaceReleased(); + if (savedSurface != null) { + savedSurface.release(); + savedSurface = null; + } + } + return isDoneWithSurface; + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {} + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) {} + } + + private class OnClickListener implements View.OnClickListener { + @Override + public void onClick(View view) { + if (delegate != null) { + delegate.onSurfaceClick(VideoSurfaceTextureImpl.this); + } else { + LogUtil.e("OnClickListener.onClick", "delegate is null"); + } + } + } +} |