summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2011-04-28 18:40:04 -0700
committerRomain Guy <romainguy@google.com>2011-04-28 18:46:19 -0700
commitaa6c24c21c727a196451332448d4e3b11a80be69 (patch)
tree27114ab3852d31723d885f3846ee874a07247126
parent9fc27819d75e24ad63d7b383d80f5cb66a577a0d (diff)
downloadframeworks_base-aa6c24c21c727a196451332448d4e3b11a80be69.zip
frameworks_base-aa6c24c21c727a196451332448d4e3b11a80be69.tar.gz
frameworks_base-aa6c24c21c727a196451332448d4e3b11a80be69.tar.bz2
New widget: TextureView
Bug #4343984 TextureView can be used to render media content (video, OpenGL, RenderScript) inside a View. The key difference with SurfaceView is that TextureView does not create a new Surface. This gives the ability to seamlessly transform, animate, fade, etc. a TextureView, which was hard if not impossible to do with a SurfaceView. A TextureView also interacts perfectly with ScrollView, ListView, etc. It allows application to embed media content in a much more flexible way than before. For instance, to render the camera preview at 50% opacity, all you need to do is the following: mTextureView.setAlpha(0.5f); Camera c = Camera.open(); c.setPreviewTexture(mTextureView.getSurfaceTexture()); c.startPreview(); TextureView uses a SurfaceTexture to get the job done. More APIs are required to make it easy to create OpenGL contexts for a TextureView. It can currently be done with a bit of JNI code. Change-Id: Iaa7953097ab5beb8437bcbbfa03b2df5b7f80cd7
-rw-r--r--api/current.txt15
-rw-r--r--core/java/android/view/GLES20Canvas.java5
-rw-r--r--core/java/android/view/GLES20Layer.java81
-rw-r--r--core/java/android/view/GLES20RenderLayer.java91
-rw-r--r--core/java/android/view/GLES20TextureLayer.java76
-rw-r--r--core/java/android/view/HardwareLayer.java12
-rw-r--r--core/java/android/view/HardwareRenderer.java52
-rw-r--r--core/java/android/view/TextureView.java299
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp22
-rw-r--r--libs/hwui/Layer.h18
-rw-r--r--libs/hwui/LayerCache.cpp2
-rw-r--r--libs/hwui/LayerRenderer.cpp47
-rw-r--r--libs/hwui/LayerRenderer.h3
-rw-r--r--libs/hwui/OpenGLRenderer.cpp57
-rw-r--r--libs/hwui/OpenGLRenderer.h13
-rw-r--r--libs/hwui/ProgramCache.cpp34
-rw-r--r--libs/hwui/ProgramCache.h5
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml14
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java87
19 files changed, 847 insertions, 86 deletions
diff --git a/api/current.txt b/api/current.txt
index ebf3893..d568254 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20962,6 +20962,21 @@ package android.view {
method public void setZOrderOnTop(boolean);
}
+ public class TextureView extends android.view.View {
+ ctor public TextureView(android.content.Context);
+ ctor public TextureView(android.content.Context, android.util.AttributeSet);
+ ctor public TextureView(android.content.Context, android.util.AttributeSet, int);
+ method public final void draw(android.graphics.Canvas);
+ method public android.graphics.SurfaceTexture getSurfaceTexture();
+ method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener();
+ method protected final void onDraw(android.graphics.Canvas);
+ method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
+ }
+
+ public static abstract interface TextureView.SurfaceTextureListener {
+ method public abstract void onSurfaceTextureAvailable(android.graphics.SurfaceTexture);
+ }
+
public class TouchDelegate {
ctor public TouchDelegate(android.graphics.Rect, android.view.View);
method public boolean onTouchEvent(android.view.MotionEvent);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b8c5c2a..cdf8954 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -160,8 +160,11 @@ class GLES20Canvas extends HardwareCanvas {
// Hardware layers
///////////////////////////////////////////////////////////////////////////
+ static native int nCreateTextureLayer(int[] layerInfo);
static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
+ static native void nUpdateTextureLayer(int layerId, int width, int height,
+ float[] textureTransform);
static native void nDestroyLayer(int layerId);
static native void nDestroyLayerDeferred(int layerId);
@@ -272,7 +275,7 @@ class GLES20Canvas extends HardwareCanvas {
}
private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
-
+
void interrupt() {
nInterrupt(mRenderer);
}
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 6000a4a..bc191a6 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -14,39 +14,21 @@
* limitations under the License.
*/
-package android.view;
-import android.graphics.Canvas;
+package android.view;
/**
* An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
*/
-class GLES20Layer extends HardwareLayer {
- private int mLayer;
-
- private int mLayerWidth;
- private int mLayerHeight;
-
- private final GLES20Canvas mCanvas;
+abstract class GLES20Layer extends HardwareLayer {
+ int mLayer;
+ Finalizer mFinalizer;
- @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
- private final Finalizer mFinalizer;
-
- GLES20Layer(int width, int height, boolean isOpaque) {
- super(width, height, isOpaque);
-
- int[] layerInfo = new int[2];
- mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
- if (mLayer != 0) {
- mLayerWidth = layerInfo[0];
- mLayerHeight = layerInfo[1];
+ GLES20Layer() {
+ }
- mCanvas = new GLES20Canvas(mLayer, !isOpaque);
- mFinalizer = new Finalizer(mLayer);
- } else {
- mCanvas = null;
- mFinalizer = null;
- }
+ GLES20Layer(int width, int height, boolean opaque) {
+ super(width, height, opaque);
}
/**
@@ -58,55 +40,14 @@ class GLES20Layer extends HardwareLayer {
return mLayer;
}
- @Override
- boolean isValid() {
- return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
- }
-
- @Override
- void resize(int width, int height) {
- if (!isValid() || width <= 0 || height <= 0) return;
-
- mWidth = width;
- mHeight = height;
-
- if (width != mLayerWidth || height != mLayerHeight) {
- int[] layerInfo = new int[2];
-
- GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo);
-
- mLayerWidth = layerInfo[0];
- mLayerHeight = layerInfo[1];
- }
- }
-
- @Override
- HardwareCanvas getCanvas() {
- return mCanvas;
- }
-
- @Override
- void end(Canvas currentCanvas) {
- if (currentCanvas instanceof GLES20Canvas) {
- ((GLES20Canvas) currentCanvas).resume();
- }
- }
-
- @Override
- HardwareCanvas start(Canvas currentCanvas) {
- if (currentCanvas instanceof GLES20Canvas) {
- ((GLES20Canvas) currentCanvas).interrupt();
- }
- return getCanvas();
- }
-
+
@Override
void destroy() {
- mFinalizer.destroy();
+ if (mFinalizer != null) mFinalizer.destroy();
mLayer = 0;
}
- private static class Finalizer {
+ static class Finalizer {
private int mLayerId;
public Finalizer(int layerId) {
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
new file mode 100644
index 0000000..7adac1c
--- /dev/null
+++ b/core/java/android/view/GLES20RenderLayer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2011 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 android.view;
+
+import android.graphics.Canvas;
+
+/**
+ * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
+ * implementation can be used a rendering target. It generates a
+ * {@link Canvas} that can be used to render into an FBO using OpenGL.
+ */
+class GLES20RenderLayer extends GLES20Layer {
+
+ private int mLayerWidth;
+ private int mLayerHeight;
+
+ private final GLES20Canvas mCanvas;
+
+ GLES20RenderLayer(int width, int height, boolean isOpaque) {
+ super(width, height, isOpaque);
+
+ int[] layerInfo = new int[2];
+ mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
+ if (mLayer != 0) {
+ mLayerWidth = layerInfo[0];
+ mLayerHeight = layerInfo[1];
+
+ mCanvas = new GLES20Canvas(mLayer, !isOpaque);
+ mFinalizer = new Finalizer(mLayer);
+ } else {
+ mCanvas = null;
+ mFinalizer = null;
+ }
+ }
+
+ @Override
+ boolean isValid() {
+ return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
+ }
+
+ @Override
+ void resize(int width, int height) {
+ if (!isValid() || width <= 0 || height <= 0) return;
+
+ mWidth = width;
+ mHeight = height;
+
+ if (width != mLayerWidth || height != mLayerHeight) {
+ int[] layerInfo = new int[2];
+
+ GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo);
+
+ mLayerWidth = layerInfo[0];
+ mLayerHeight = layerInfo[1];
+ }
+ }
+
+ @Override
+ HardwareCanvas getCanvas() {
+ return mCanvas;
+ }
+
+ @Override
+ void end(Canvas currentCanvas) {
+ if (currentCanvas instanceof GLES20Canvas) {
+ ((GLES20Canvas) currentCanvas).resume();
+ }
+ }
+
+ @Override
+ HardwareCanvas start(Canvas currentCanvas) {
+ if (currentCanvas instanceof GLES20Canvas) {
+ ((GLES20Canvas) currentCanvas).interrupt();
+ }
+ return getCanvas();
+ }
+}
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
new file mode 100644
index 0000000..21fbdfc
--- /dev/null
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 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 android.view;
+
+import android.graphics.Canvas;
+import android.graphics.SurfaceTexture;
+
+/**
+ * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
+ * implementation can be used as a texture. Rendering into this
+ * layer is not controlled by a {@link HardwareCanvas}.
+ */
+class GLES20TextureLayer extends GLES20Layer {
+ private int mTexture;
+ private SurfaceTexture mSurface;
+
+ GLES20TextureLayer() {
+ int[] layerInfo = new int[2];
+ mLayer = GLES20Canvas.nCreateTextureLayer(layerInfo);
+
+ if (mLayer != 0) {
+ mTexture = layerInfo[0];
+ mFinalizer = new Finalizer(mLayer);
+ } else {
+ mFinalizer = null;
+ }
+ }
+
+ @Override
+ boolean isValid() {
+ return mLayer != 0 && mTexture != 0;
+ }
+
+ @Override
+ void resize(int width, int height) {
+ }
+
+ @Override
+ HardwareCanvas getCanvas() {
+ return null;
+ }
+
+ @Override
+ HardwareCanvas start(Canvas currentCanvas) {
+ return null;
+ }
+
+ @Override
+ void end(Canvas currentCanvas) {
+ }
+
+ SurfaceTexture getSurfaceTexture() {
+ if (mSurface == null) {
+ mSurface = new SurfaceTexture(mTexture);
+ }
+ return mSurface;
+ }
+
+ void update(int width, int height, float[] textureTransform) {
+ GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, textureTransform);
+ }
+}
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index d01b8ce..86dec3f 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -26,12 +26,24 @@ import android.graphics.Canvas;
* drawn several times.
*/
abstract class HardwareLayer {
+ /**
+ * Indicates an unknown dimension (width or height.)
+ */
+ static final int DIMENSION_UNDEFINED = -1;
+
int mWidth;
int mHeight;
final boolean mOpaque;
/**
+ * Creates a new hardware layer with undefined dimensions.
+ */
+ HardwareLayer() {
+ this(DIMENSION_UNDEFINED, DIMENSION_UNDEFINED, false);
+ }
+
+ /**
* Creates a new hardware layer at least as large as the supplied
* dimensions.
*
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 66f37f2..5b2983d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -20,6 +20,7 @@ package android.view;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.os.*;
import android.util.EventLog;
import android.util.Log;
@@ -166,6 +167,14 @@ public abstract class HardwareRenderer {
abstract DisplayList createDisplayList(View v);
/**
+ * Creates a new hardware layer. A hardware layer built by calling this
+ * method will be treated as a texture layer, instead of as a render target.
+ *
+ * @return A hardware layer
+ */
+ abstract HardwareLayer createHardwareLayer();
+
+ /**
* Creates a new hardware layer.
*
* @param width The minimum width of the layer
@@ -175,6 +184,29 @@ public abstract class HardwareRenderer {
* @return A hardware layer
*/
abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
+
+ /**
+ * Creates a new {@link SurfaceTexture} that can be used to render into the
+ * specified hardware layer.
+ *
+ *
+ * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
+ *
+ * @return A {@link SurfaceTexture}
+ */
+ abstract SurfaceTexture createSuraceTexture(HardwareLayer layer);
+
+ /**
+ * Updates the specified layer.
+ *
+ * @param layer The hardware layer to update
+ * @param width The layer's width
+ * @param height The layer's height
+ * @param textureTransform A 4x4 column-first transform matrix to apply to
+ * texture coordinates
+ */
+ abstract void updateTextureLayer(HardwareLayer layer, int width, int height,
+ float[] textureTransform);
/**
* Initializes the hardware renderer for the specified surface and setup the
@@ -856,10 +888,26 @@ public abstract class HardwareRenderer {
DisplayList createDisplayList(View v) {
return new GLES20DisplayList(v);
}
-
+
+ @Override
+ HardwareLayer createHardwareLayer() {
+ return new GLES20TextureLayer();
+ }
+
@Override
HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
- return new GLES20Layer(width, height, isOpaque);
+ return new GLES20RenderLayer(width, height, isOpaque);
+ }
+
+ @Override
+ SurfaceTexture createSuraceTexture(HardwareLayer layer) {
+ return ((GLES20TextureLayer) layer).getSurfaceTexture();
+ }
+
+ @Override
+ void updateTextureLayer(HardwareLayer layer, int width, int height,
+ float[] textureTransform) {
+ ((GLES20TextureLayer) layer).update(width, height, textureTransform);
}
static HardwareRenderer create(boolean translucent) {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
new file mode 100644
index 0000000..5ece15c
--- /dev/null
+++ b/core/java/android/view/TextureView.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2011 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 android.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.SurfaceTexture;
+import android.util.AttributeSet;
+import android.util.Log;
+
+/**
+ * <p>A TextureView can be used to display a content stream. Such a content
+ * stream can for instance be a video or an OpenGL scene. The content stream
+ * can come from the application's process as well as a remote process.</p>
+ *
+ * <p>TextureView can only be used in a hardware accelerated window. When
+ * rendered in software, TextureView will draw nothing.</p>
+ *
+ * <p>Unlike {@link SurfaceView}, TextureView does not create a separate
+ * window but behaves as a regular View. This key difference allows a
+ * TextureView to be moved, transformed, animated, etc. For instance, you
+ * can make a TextureView semi-translucent by calling
+ * <code>myView.setAlpha(0.5f)</code>.</p>
+ *
+ * <p>Using a TextureView is simple: all you need to do is get its
+ * {@link SurfaceTexture}. The {@link SurfaceTexture} can then be used to
+ * render content. The following example demonstrates how to render the
+ * camera preview into a TextureView:</p>
+ *
+ * <pre>
+ * public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {
+ * private Camera mCamera;
+ * private TextureView mTextureView;
+ *
+ * @Override
+ * protected void onCreate(Bundle savedInstanceState) {
+ * super.onCreate(savedInstanceState);
+ *
+ * mTextureView = new TextureView(this);
+ * mTextureView.setSurfaceTextureListener(this);
+ *
+ * setContentView(mTextureView);
+ * }
+ *
+ * @Override
+ * protected void onDestroy() {
+ * super.onDestroy();
+ *
+ * mCamera.stopPreview();
+ * mCamera.release();
+ * }
+ *
+ * @Override
+ * public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ * mCamera = Camera.open();
+ *
+ * try {
+ * mCamera.setPreviewTexture(surface);
+ * mCamera.startPreview();
+ * } catch (IOException ioe) {
+ * // Something bad happened
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ * <p>A TextureView's SurfaceTexture can be obtained either by invoking
+ * {@link #getSurfaceTexture()} or by using a {@link SurfaceTextureListener}.
+ * It is important to know that a SurfaceTexture is available only after the
+ * TextureView is attached to a window (and {@link #onAttachedToWindow()} has
+ * been invoked.) It is therefore highly recommended you use a listener to
+ * be notified when the SurfaceTexture becomes available.</p>
+ *
+ * @see SurfaceView
+ * @see SurfaceTexture
+ */
+public class TextureView extends View {
+ private HardwareLayer mLayer;
+ private SurfaceTexture mSurface;
+ private SurfaceTextureListener mListener;
+
+ private final float[] mTextureTransform = new float[16];
+
+ private final Runnable mUpdateLayerAction = new Runnable() {
+ @Override
+ public void run() {
+ updateLayer();
+ }
+ };
+
+ /**
+ * Creates a new TextureView.
+ *
+ * @param context The context to associate this view with.
+ */
+ public TextureView(Context context) {
+ super(context);
+ init();
+ }
+
+ /**
+ * Creates a new TextureView.
+ *
+ * @param context The context to associate this view with.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ public TextureView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * Creates a new TextureView.
+ *
+ * @param context The context to associate this view with.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ * @param defStyle The default style to apply to this view. If 0, no style
+ * will be applied (beyond what is included in the theme). This may
+ * either be an attribute resource, whose value will be retrieved
+ * from the current theme, or an explicit style resource.
+ */
+ @SuppressWarnings({"UnusedDeclaration"})
+ public TextureView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init() {
+ mLayerPaint = new Paint();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (!isHardwareAccelerated()) {
+ Log.w("TextureView", "A TextureView or a subclass can only be "
+ + "used with hardware acceleration enabled.");
+ }
+ }
+
+ /**
+ * 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
+ * method will however be taken into account when rendering the content of
+ * this TextureView.
+ *
+ * @param layerType The ype of layer to use with this view, must be one of
+ * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
+ * {@link #LAYER_TYPE_HARDWARE}
+ * @param paint The paint used to compose the layer. This argument is optional
+ * and can be null. It is ignored when the layer type is
+ * {@link #LAYER_TYPE_NONE}
+ */
+ @Override
+ public void setLayerType(int layerType, Paint paint) {
+ if (paint != mLayerPaint) {
+ mLayerPaint = paint;
+ invalidate();
+ }
+ }
+
+ /**
+ * Always returns {@link #LAYER_TYPE_HARDWARE}.
+ */
+ @Override
+ public int getLayerType() {
+ return LAYER_TYPE_HARDWARE;
+ }
+
+ /**
+ * Calling this method has no effect.
+ */
+ @Override
+ public void buildLayer() {
+ }
+
+ /**
+ * Subclasses of TextureView cannot do their own rendering
+ * with the {@link Canvas} object.
+ *
+ * @param canvas The Canvas to which the View is rendered.
+ */
+ @Override
+ public final void draw(Canvas canvas) {
+ super.draw(canvas);
+ }
+
+ /**
+ * Subclasses of TextureView cannot do their own rendering
+ * with the {@link Canvas} object.
+ *
+ * @param canvas The Canvas to which the View is rendered.
+ */
+ @Override
+ protected final void onDraw(Canvas canvas) {
+ }
+
+ @Override
+ HardwareLayer getHardwareLayer() {
+ if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
+ return null;
+ }
+
+ if (mLayer == null) {
+ mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer();
+ mSurface = mAttachInfo.mHardwareRenderer.createSuraceTexture(mLayer);
+
+ mSurface.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
+ @Override
+ public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ // Per SurfaceTexture's documentation, the callback may be invoked
+ // from an arbitrary thread
+ post(mUpdateLayerAction);
+ }
+ });
+
+ if (mListener != null) {
+ mListener.onSurfaceTextureAvailable(mSurface);
+ }
+ }
+
+ return mLayer;
+ }
+
+ private void updateLayer() {
+ if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
+ return;
+ }
+
+ mSurface.updateTexImage();
+ mSurface.getTransformMatrix(mTextureTransform);
+
+ mAttachInfo.mHardwareRenderer.updateTextureLayer(mLayer, getWidth(), getHeight(),
+ mTextureTransform);
+
+ invalidate();
+ }
+
+ /**
+ * Returns the {@link SurfaceTexture} used by this view. This method
+ * may return null if the view is not attached to a window.
+ */
+ public SurfaceTexture getSurfaceTexture() {
+ return mSurface;
+ }
+
+ /**
+ * Returns the {@link SurfaceTextureListener} currently associated with this
+ * texture view.
+ *
+ * @see #setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener)
+ * @see SurfaceTextureListener
+ */
+ public SurfaceTextureListener getSurfaceTextureListener() {
+ return mListener;
+ }
+
+ /**
+ * Sets the {@link SurfaceTextureListener} used to listen to surface
+ * texture events.
+ *
+ * @see #getSurfaceTextureListener()
+ * @see SurfaceTextureListener
+ */
+ public void setSurfaceTextureListener(SurfaceTextureListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * This listener can be used to be notified when the surface texture
+ * associated with this texture view is available.
+ */
+ public static interface SurfaceTextureListener {
+ /**
+ * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
+ *
+ * @param surface The surface returned by
+ * {@link android.view.TextureView#getSurfaceTexture()}
+ */
+ public void onSurfaceTextureAvailable(SurfaceTexture surface);
+ }
+}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 314c2ee..af7639a 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -539,6 +539,19 @@ static OpenGLRenderer* android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env
return NULL;
}
+static Layer* android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject clazz,
+ jintArray layerInfo) {
+ Layer* layer = LayerRenderer::createTextureLayer();
+
+ if (layer) {
+ jint* storage = env->GetIntArrayElements(layerInfo, NULL);
+ storage[0] = layer->texture;
+ env->ReleaseIntArrayElements(layerInfo, storage, 0);
+ }
+
+ return layer;
+}
+
static Layer* android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz,
jint width, jint height, jboolean isOpaque, jintArray layerInfo) {
Layer* layer = LayerRenderer::createLayer(width, height, isOpaque);
@@ -563,6 +576,13 @@ static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
env->ReleaseIntArrayElements(layerInfo, storage, 0);
}
+static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
+ Layer* layer, jint width, jint height, jfloatArray texTransform) {
+ jfloat* transform = env->GetFloatArrayElements(texTransform, NULL);
+ LayerRenderer::updateTextureLayer(layer, width, height, transform);
+ env->ReleaseFloatArrayElements(texTransform, transform, 0);
+}
+
static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, Layer* layer) {
LayerRenderer::destroyLayer(layer);
}
@@ -696,6 +716,8 @@ static JNINativeMethod gMethods[] = {
{ "nCreateLayerRenderer", "(I)I", (void*) android_view_GLES20Canvas_createLayerRenderer },
{ "nCreateLayer", "(IIZ[I)I", (void*) android_view_GLES20Canvas_createLayer },
{ "nResizeLayer", "(III[I)V" , (void*) android_view_GLES20Canvas_resizeLayer },
+ { "nCreateTextureLayer", "([I)I", (void*) android_view_GLES20Canvas_createTextureLayer },
+ { "nUpdateTextureLayer", "(III[F)V" , (void*) android_view_GLES20Canvas_updateTextureLayer },
{ "nDestroyLayer", "(I)V", (void*) android_view_GLES20Canvas_destroyLayer },
{ "nDestroyLayerDeferred", "(I)V", (void*) android_view_GLES20Canvas_destroyLayerDeferred },
{ "nDrawLayer", "(IIFFI)V", (void*) android_view_GLES20Canvas_drawLayer },
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 6c4a2a9..16566b8 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -45,6 +45,8 @@ struct Layer {
mesh = NULL;
meshIndices = NULL;
meshElementCount = 0;
+ isCacheable = true;
+ isTextureLayer = false;
}
~Layer() {
@@ -137,6 +139,22 @@ struct Layer {
TextureVertex* mesh;
uint16_t* meshIndices;
GLsizei meshElementCount;
+
+ /**
+ * If set to true (by default), the layer can be reused.
+ */
+ bool isCacheable;
+
+ /**
+ * When set to true, this layer must be treated as a texture
+ * layer.
+ */
+ bool isTextureLayer;
+
+ /**
+ * Optional texture coordinates transform.
+ */
+ mat4 texTransform;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index a9710ad..b2d795f 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -154,6 +154,8 @@ bool LayerCache::resize(Layer* layer, const uint32_t width, const uint32_t heigh
}
bool LayerCache::put(Layer* layer) {
+ if (!layer->isCacheable) return false;
+
const uint32_t size = layer->width * layer->height * 4;
// Don't even try to cache a layer that's bigger than the cache
if (size < mMaxSize) {
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index ca1e7ae..e167336 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -20,6 +20,7 @@
#include "LayerCache.h"
#include "LayerRenderer.h"
+#include "Matrix.h"
#include "Properties.h"
#include "Rect.h"
@@ -165,6 +166,40 @@ void LayerRenderer::generateMesh() {
// Layers management
///////////////////////////////////////////////////////////////////////////////
+Layer* LayerRenderer::createTextureLayer() {
+ LAYER_RENDERER_LOGD("Creating new texture layer");
+
+ Layer* layer = new Layer(0, 0);
+ layer->isCacheable = false;
+ layer->isTextureLayer = true;
+ layer->blend = true;
+ layer->empty = true;
+ layer->fbo = 0;
+ layer->colorFilter = NULL;
+ layer->fbo = 0;
+ layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
+ layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
+ layer->alpha = 255;
+ layer->mode = SkXfermode::kSrcOver_Mode;
+ layer->colorFilter = NULL;
+ layer->region.clear();
+
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenTextures(1, &layer->texture);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, layer->texture);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ return layer;
+}
+
Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height);
@@ -244,6 +279,18 @@ bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
return true;
}
+void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+ float* transform) {
+ if (layer) {
+ layer->width = width;
+ layer->height = height;
+ layer->layer.set(0.0f, 0.0f, width, height);
+ layer->region.set(width, height);
+ layer->regionRect.set(0.0f, 0.0f, width, height);
+ layer->texTransform.load(transform);
+ }
+}
+
void LayerRenderer::destroyLayer(Layer* layer) {
if (layer) {
LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo);
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index d2f565e..b3cd5db 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -53,8 +53,11 @@ public:
Region* getRegion();
GLint getTargetFbo();
+ static Layer* createTextureLayer();
static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
+ static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+ float* transform);
static void destroyLayer(Layer* layer);
static void destroyLayerDeferred(Layer* layer);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e926d99..4dde342 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -633,15 +633,43 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
}
}
+void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
+ float alpha = layer->alpha / 255.0f;
+
+ setupDraw();
+ setupDrawWithExternalTexture();
+ setupDrawColor(alpha, alpha, alpha, alpha);
+ setupDrawColorFilter();
+ setupDrawBlending(layer->blend, layer->mode);
+ setupDrawProgram();
+ setupDrawModelView(rect.left, rect.top, rect.right, rect.bottom);
+ setupDrawPureColorUniforms();
+ setupDrawColorFilterUniforms();
+ setupDrawExternalTexture(layer->texture);
+ setupDrawTextureTransform(layer->texTransform);
+ setupDrawMesh(&mMeshVertices[0].position[0], &mMeshVertices[0].texture[0]);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
+
+ finishDrawTexture();
+}
+
void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
- const Rect& texCoords = layer->texCoords;
- resetDrawTextureTexCoords(texCoords.left, texCoords.top, texCoords.right, texCoords.bottom);
+ if (!layer->isTextureLayer) {
+ const Rect& texCoords = layer->texCoords;
+ resetDrawTextureTexCoords(texCoords.left, texCoords.top,
+ texCoords.right, texCoords.bottom);
- drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
- layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
- &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
+ drawTextureMesh(rect.left, rect.top, rect.right, rect.bottom, layer->texture,
+ layer->alpha / 255.0f, layer->mode, layer->blend, &mMeshVertices[0].position[0],
+ &mMeshVertices[0].texture[0], GL_TRIANGLE_STRIP, gMeshCount, swap, swap);
- resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ } else {
+ resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
+ drawTextureLayer(layer, rect);
+ resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+ }
}
void OpenGLRenderer::composeLayerRegion(Layer* layer, const Rect& rect) {
@@ -882,6 +910,10 @@ void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
mDescription.hasAlpha8Texture = isAlpha8;
}
+void OpenGLRenderer::setupDrawWithExternalTexture() {
+ mDescription.hasExternalTexture = true;
+}
+
void OpenGLRenderer::setupDrawAALine() {
mDescription.hasWidth = true;
}
@@ -1055,6 +1087,19 @@ void OpenGLRenderer::setupDrawTexture(GLuint texture) {
glEnableVertexAttribArray(mTexCoordsSlot);
}
+void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
+ bindExternalTexture(texture);
+ glUniform1i(mCaches.currentProgram->getUniform("sampler"), mTextureUnit++);
+
+ mTexCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
+ glEnableVertexAttribArray(mTexCoordsSlot);
+}
+
+void OpenGLRenderer::setupDrawTextureTransform(mat4& transform) {
+ glUniformMatrix4fv(mCaches.currentProgram->getUniform("mainTextureTransform"), 1,
+ GL_FALSE, &transform.data[0]);
+}
+
void OpenGLRenderer::setupDrawMesh(GLvoid* vertices, GLvoid* texCoords, GLuint vbo) {
if (!vertices) {
mCaches.bindMeshBuffer(vbo == 0 ? mCaches.meshBuffer : vbo);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 0276095..a3e12f6 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -248,6 +248,8 @@ private:
*/
void composeLayerRect(Layer* layer, const Rect& rect, bool swap = false);
+ void drawTextureLayer(Layer* layer, const Rect& rect);
+
/**
* Mark the layer as dirty at the specified coordinates. The coordinates
* are transformed with the supplied matrix.
@@ -400,6 +402,14 @@ private:
}
/**
+ * Binds the specified EGLImage texture. The texture unit must have been selected
+ * prior to calling this method.
+ */
+ inline void bindExternalTexture(GLuint texture) {
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
+ }
+
+ /**
* Sets the wrap modes for the specified texture. The wrap modes are modified
* only when needed.
*/
@@ -438,6 +448,7 @@ private:
* Various methods to setup OpenGL rendering.
*/
void setupDrawWithTexture(bool isAlpha8 = false);
+ void setupDrawWithExternalTexture();
void setupDrawAALine();
void setupDrawPoint(float pointSize);
void setupDrawColor(int color);
@@ -466,6 +477,8 @@ private:
void setupDrawColorFilterUniforms();
void setupDrawSimpleMesh();
void setupDrawTexture(GLuint texture);
+ void setupDrawExternalTexture(GLuint texture);
+ void setupDrawTextureTransform(mat4& transform);
void setupDrawMesh(GLvoid* vertices, GLvoid* texCoords = NULL, GLuint vbo = 0);
void setupDrawVertices(GLvoid* vertices);
void setupDrawAALine(GLvoid* vertices, GLvoid* distanceCoords, float strokeWidth);
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 80b1917..62ac2ba 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -41,6 +41,8 @@ const char* gVS_Header_Attributes_TexCoords =
"attribute vec2 texCoords;\n";
const char* gVS_Header_Attributes_Distance =
"attribute float vtxDistance;\n";
+const char* gVS_Header_Uniforms_TextureTransform =
+ "uniform mat4 mainTextureTransform;\n";
const char* gVS_Header_Uniforms =
"uniform mat4 transform;\n";
const char* gVS_Header_Uniforms_IsPoint =
@@ -76,6 +78,8 @@ const char* gVS_Main =
"\nvoid main(void) {\n";
const char* gVS_Main_OutTexCoords =
" outTexCoords = texCoords;\n";
+const char* gVS_Main_OutTransformedTexCoords =
+ " outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
const char* gVS_Main_OutGradient[3] = {
// Linear
" linear = vec2((screenSpace * position).x, 0.5);\n",
@@ -103,6 +107,8 @@ const char* gVS_Footer =
const char* gFS_Header_Extension_FramebufferFetch =
"#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
+const char* gFS_Header_Extension_ExternalTexture =
+ "#extension GL_OES_EGL_image_external : require\n\n";
const char* gFS_Header =
"precision mediump float;\n\n";
const char* gFS_Uniforms_Color =
@@ -116,6 +122,8 @@ const char* gFS_Header_Uniforms_PointHasBitmap =
"uniform float pointSize;\n";
const char* gFS_Uniforms_TextureSampler =
"uniform sampler2D sampler;\n";
+const char* gFS_Uniforms_ExternalTextureSampler =
+ "uniform samplerExternalOES sampler;\n";
const char* gFS_Uniforms_GradientSampler[3] = {
// Linear
"uniform sampler2D gradientSampler;\n",
@@ -369,7 +377,7 @@ Program* ProgramCache::generateProgram(const ProgramDescription& description, pr
String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
// Add attributes
String8 shader(gVS_Header_Attributes);
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Attributes_TexCoords);
}
if (description.hasWidth) {
@@ -377,6 +385,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
}
// Uniforms
shader.append(gVS_Header_Uniforms);
+ if (description.hasExternalTexture) {
+ shader.append(gVS_Header_Uniforms_TextureTransform);
+ }
if (description.hasGradient) {
shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]);
}
@@ -387,7 +398,7 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
shader.append(gVS_Header_Uniforms_IsPoint);
}
// Varyings
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
}
if (description.hasWidth) {
@@ -407,6 +418,9 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description
if (description.hasTexture) {
shader.append(gVS_Main_OutTexCoords);
}
+ if (description.hasExternalTexture) {
+ shader.append(gVS_Main_OutTransformedTexCoords);
+ }
if (description.hasWidth) {
shader.append(gVS_Main_Width);
}
@@ -440,11 +454,14 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (blendFramebuffer) {
shader.append(gFS_Header_Extension_FramebufferFetch);
}
+ if (description.hasExternalTexture) {
+ shader.append(gFS_Header_Extension_ExternalTexture);
+ }
shader.append(gFS_Header);
// Varyings
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
shader.append(gVS_Header_Varyings_HasTexture);
}
if (description.hasWidth) {
@@ -461,7 +478,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
// Uniforms
int modulateOp = MODULATE_OP_NO_MODULATE;
- const bool singleColor = !description.hasTexture &&
+ const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
!description.hasGradient && !description.hasBitmap;
if (description.modulate || singleColor) {
@@ -471,6 +488,9 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
if (description.hasTexture) {
shader.append(gFS_Uniforms_TextureSampler);
}
+ if (description.hasExternalTexture) {
+ shader.append(gFS_Uniforms_ExternalTextureSampler);
+ }
if (description.hasWidth) {
shader.append(gFS_Uniforms_Width);
}
@@ -487,11 +507,11 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
bool fast = false;
const bool noShader = !description.hasGradient && !description.hasBitmap;
- const bool singleTexture = description.hasTexture &&
+ const bool singleTexture = (description.hasTexture || description.hasExternalTexture) &&
!description.hasAlpha8Texture && noShader;
const bool singleA8Texture = description.hasTexture &&
description.hasAlpha8Texture && noShader;
- const bool singleGradient = !description.hasTexture &&
+ const bool singleGradient = !description.hasTexture && !description.hasExternalTexture &&
description.hasGradient && !description.hasBitmap &&
description.gradientType == ProgramDescription::kGradientLinear;
@@ -554,7 +574,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti
// Begin the shader
shader.append(gFS_Main); {
// Stores the result in fragColor directly
- if (description.hasTexture) {
+ if (description.hasTexture || description.hasExternalTexture) {
if (description.hasAlpha8Texture) {
if (!description.hasGradient && !description.hasBitmap) {
shader.append(gFS_Main_FetchA8Texture[modulateOp]);
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 18d98cb..70909fd 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -77,6 +77,8 @@ namespace uirenderer {
#define PROGRAM_HAS_WIDTH_SHIFT 37
+#define PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT 38
+
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
@@ -113,6 +115,7 @@ struct ProgramDescription {
// Texturing
bool hasTexture;
bool hasAlpha8Texture;
+ bool hasExternalTexture;
// Modulate, this should only be set when setColor() return true
bool modulate;
@@ -151,6 +154,7 @@ struct ProgramDescription {
void reset() {
hasTexture = false;
hasAlpha8Texture = false;
+ hasExternalTexture = false;
hasWidth = false;
@@ -240,6 +244,7 @@ struct ProgramDescription {
if (modulate) key |= programid(0x1) << PROGRAM_MODULATE_SHIFT;
if (isPoint) key |= programid(0x1) << PROGRAM_IS_POINT_SHIFT;
if (hasWidth) key |= programid(0x1) << PROGRAM_HAS_WIDTH_SHIFT;
+ if (hasExternalTexture) key |= programid(0x1) << PROGRAM_HAS_EXTERNAL_TEXTURE_SHIFT;
return key;
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c763b1d..3a3bfd8 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -18,6 +18,11 @@
package="com.android.test.hwui">
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CAMERA" />
+
+ <uses-feature android:name="android.hardware.camera" />
+ <uses-feature android:name="android.hardware.camera.autofocus" />
+
<uses-sdk android:minSdkVersion="11" />
<application
@@ -25,6 +30,15 @@
android:hardwareAccelerated="true">
<activity
+ android:name="TextureViewActivity"
+ android:label="_TextureView">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="BitmapMeshActivity"
android:label="_BitmapMesh">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
new file mode 100644
index 0000000..4726672
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 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.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.io.IOException;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class TextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
+ private Camera mCamera;
+ private TextureView mTextureView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ setContentView(mTextureView, new FrameLayout.LayoutParams(500, 400, Gravity.CENTER));
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ mCamera.stopPreview();
+ mCamera.release();
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface) {
+ mCamera = Camera.open();
+
+ try {
+ mCamera.setPreviewTexture(surface);
+ } catch (IOException t) {
+ android.util.Log.e("TextureView", "Cannot set preview texture target!", t);
+ }
+
+ mCamera.startPreview();
+
+ 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() {
+ @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();
+ }
+}