Add onSurfaceTextureDestroyed() callback.
This is needed for Renderscript and it also makes implementations
of TextureView cleaner. This change also hooks up the onSurfaceTextureSizeCHanged()
callback whenever the view size changes.
Change-Id: I2f972ee4504d800329defefacf32cf20547d31a3
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 755ecf5..bc1ad3c 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -56,14 +56,7 @@
* setContentView(mTextureView);
* }
*
- * protected void onDestroy() {
- * super.onDestroy();
- *
- * mCamera.stopPreview();
- * mCamera.release();
- * }
- *
- * public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ * public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
* mCamera = Camera.open();
*
* try {
@@ -77,6 +70,11 @@
* public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
* // Ignored, Camera does all the work for us
* }
+ *
+ * public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ * mCamera.stopPreview();
+ * mCamera.release();
+ * }
* }
* </pre>
*
@@ -155,6 +153,21 @@
}
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (isHardwareAccelerated() && mLayer != null) {
+ if (mListener != null) {
+ mListener.onSurfaceTextureDestroyed(mSurface);
+ }
+
+ mLayer.destroy();
+ mSurface = null;
+ mLayer = null;
+ }
+ }
+
/**
* The layer type of a TextureView is ignored since a TextureView is always
* considered to act as a hardware layer. The optional paint supplied to this
@@ -217,6 +230,9 @@
super.onSizeChanged(w, h, oldw, oldh);
if (mSurface != null) {
nSetDefaultBufferSize(mSurface.mSurfaceTexture, getWidth(), getHeight());
+ if (mListener != null) {
+ mListener.onSurfaceTextureSizeChanged(mSurface, getWidth(), getHeight());
+ }
}
}
@@ -242,7 +258,7 @@
mSurface.setOnFrameAvailableListener(mUpdateListener);
if (mListener != null) {
- mListener.onSurfaceTextureAvailable(mSurface);
+ mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
}
}
@@ -316,8 +332,10 @@
*
* @param surface The surface returned by
* {@link android.view.TextureView#getSurfaceTexture()}
+ * @param width The width of the surface
+ * @param height The height of the surface
*/
- public void onSurfaceTextureAvailable(SurfaceTexture surface);
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height);
/**
* Invoked when the {@link SurfaceTexture}'s buffers size changed.
@@ -328,6 +346,15 @@
* @param height The new height of the surface
*/
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height);
+
+ /**
+ * Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
+ * After this method is invoked, no rendering should happen inside the surface
+ * texture.
+ *
+ * @param surface The surface about to be destroyed
+ */
+ public void onSurfaceTextureDestroyed(SurfaceTexture surface);
}
private static native void nSetDefaultBufferSize(int surfaceTexture, int width, int height);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index 7f97098..9bb5ba8 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -52,13 +52,7 @@
}
@Override
- protected void onDestroy() {
- super.onDestroy();
- mRenderThread.finish();
- }
-
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mRenderThread = new RenderThread(surface);
mRenderThread.start();
@@ -81,6 +75,16 @@
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
+ @Override
+ public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ mRenderThread.finish();
+ try {
+ mRenderThread.join();
+ } catch (InterruptedException e) {
+ Log.e(RenderThread.LOG_TAG, "Could not wait for render thread");
+ }
+ }
+
private static class RenderThread extends Thread {
private static final String LOG_TAG = "GLTextureView";
@@ -108,26 +112,23 @@
public void run() {
initGL();
- float red = 0.0f;
+ float red = 1.0f;
while (!mFinished) {
checkCurrent();
+ Log.d(LOG_TAG, "Rendering frame");
+
GLES20.glClearColor(red, 0.0f, 0.0f, 1.0f);
- int error = GLES20.glGetError();
- if (error != GLES20.GL_NO_ERROR) {
- Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
- }
+ checkGlError();
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
- error = GLES20.glGetError();
- if (error != GLES20.GL_NO_ERROR) {
- Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
- }
+ checkGlError();
if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
throw new RuntimeException("Cannot swap buffers");
}
-
+ checkEglError();
+
try {
Thread.sleep(20);
} catch (InterruptedException e) {
@@ -141,6 +142,20 @@
finishGL();
}
+ private void checkEglError() {
+ int error = mEgl.eglGetError();
+ if (error != EGL10.EGL_SUCCESS) {
+ Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error));
+ }
+ }
+
+ private void checkGlError() {
+ int error = GLES20.glGetError();
+ if (error != GLES20.GL_NO_ERROR) {
+ Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+ }
+ }
+
private void finishGL() {
mEgl.eglDestroyContext(mEglDisplay, mEglContext);
mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index 2feda57..fa2e39a 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -16,6 +16,7 @@
package com.android.test.hwui;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
@@ -25,6 +26,7 @@
import android.view.Gravity;
import android.view.TextureView;
import android.view.View;
+import android.widget.Button;
import android.widget.FrameLayout;
import java.io.IOException;
@@ -33,27 +35,44 @@
public class TextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
private Camera mCamera;
private TextureView mTextureView;
+ private FrameLayout mContent;
+ private AnimatorSet mAnimatorSet;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mContent = new FrameLayout(this);
+
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
- setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ Button button = new Button(this);
+ button.setText("Remove/Add");
+ button.setOnClickListener(new View.OnClickListener() {
+ private boolean mAdded = true;
+
+ @Override
+ public void onClick(View v) {
+ if (mAdded) {
+ mAnimatorSet.cancel();
+ mContent.removeView(mTextureView);
+ } else {
+ mContent.addView(mTextureView);
+ }
+ mAdded = !mAdded;
+ }
+ });
+
+ mContent.addView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ mContent.addView(button, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
+ setContentView(mContent);
}
@Override
- protected void onDestroy() {
- super.onDestroy();
-
- mCamera.stopPreview();
- mCamera.release();
- }
-
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();
try {
@@ -66,27 +85,35 @@
mTextureView.setCameraDistance(5000);
- ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
- animator.setRepeatMode(ObjectAnimator.REVERSE);
- animator.setRepeatCount(ObjectAnimator.INFINITE);
- animator.setDuration(4000);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ ObjectAnimator rotationY = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+ rotationY.setRepeatMode(ObjectAnimator.REVERSE);
+ rotationY.setRepeatCount(ObjectAnimator.INFINITE);
+ rotationY.setDuration(4000);
+ rotationY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
((View) mTextureView.getParent()).invalidate();
}
});
- animator.start();
- animator = ObjectAnimator.ofFloat(mTextureView, "alpha", 1.0f, 0.0f);
- animator.setRepeatMode(ObjectAnimator.REVERSE);
- animator.setRepeatCount(ObjectAnimator.INFINITE);
- animator.setDuration(4000);
- animator.start();
+ ObjectAnimator alpha = ObjectAnimator.ofFloat(mTextureView, "alpha", 1.0f, 0.0f);
+ alpha.setRepeatMode(ObjectAnimator.REVERSE);
+ alpha.setRepeatCount(ObjectAnimator.INFINITE);
+ alpha.setDuration(4000);
+
+ mAnimatorSet = new AnimatorSet();
+ mAnimatorSet.play(alpha).with(rotationY);
+ mAnimatorSet.start();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, the Camera does all the work for us
}
+
+ @Override
+ public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ mCamera.stopPreview();
+ mCamera.release();
+ }
}