diff --git a/api/current.xml b/api/current.xml
index 610542d5c0d42..f7721c4c58eeb 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -5900,6 +5900,17 @@
visibility="public"
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *
+ * Starting with Android 3.0, the preferred way of animating views is to use the
+ * {@link android.animation} package APIs.
+ *
*
*
* Security
@@ -569,6 +572,7 @@ import java.util.WeakHashMap;
* See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}.
*
*
+ * @attr ref android.R.styleable#View_alpha
* @attr ref android.R.styleable#View_background
* @attr ref android.R.styleable#View_clickable
* @attr ref android.R.styleable#View_contentDescription
@@ -584,6 +588,7 @@ import java.util.WeakHashMap;
* @attr ref android.R.styleable#View_focusableInTouchMode
* @attr ref android.R.styleable#View_hapticFeedbackEnabled
* @attr ref android.R.styleable#View_keepScreenOn
+ * @attr ref android.R.styleable#View_layerType
* @attr ref android.R.styleable#View_longClickable
* @attr ref android.R.styleable#View_minHeight
* @attr ref android.R.styleable#View_minWidth
@@ -2151,6 +2156,69 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*/
public static final int SCROLLBAR_POSITION_RIGHT = 2;
+ /**
+ * Indicates that the view does not have a layer.
+ *
+ * @see #getLayerType()
+ * @see #setLayerType(int, android.graphics.Paint)
+ * @see #LAYER_TYPE_SOFTWARE
+ * @see #LAYER_TYPE_HARDWARE
+ */
+ public static final int LAYER_TYPE_NONE = 0;
+
+ /**
+ * Indicates that the view has a software layer. A software layer is backed
+ * by a bitmap and causes the view to be rendered using Android's software
+ * rendering pipeline, even if hardware acceleration is enabled.
+ *
+ * Software layers have various usages:
+ * When the application is not using hardware acceleration, a software layer
+ * is useful to apply a specific color filter and/or blending mode and/or
+ * translucency to a view and all its children.
+ * When the application is using hardware acceleration, a software layer
+ * is useful to render drawing primitives not supported by the hardware
+ * accelerated pipeline. It can also be used to cache a complex view tree
+ * into a texture and reduce the complexity of drawing operations. For instance,
+ * when animating a complex view tree with a translation, a software layer can
+ * be used to render the view tree only once.
+ * Software layers should be avoided when the affected view tree updates
+ * often. Every update will require to re-render the software layer, which can
+ * potentially be slow (particularly when hardware acceleration is turned on
+ * since the layer will have to be uploaded into a hardware texture after every
+ * update.)
+ *
+ * @see #getLayerType()
+ * @see #setLayerType(int, android.graphics.Paint)
+ * @see #LAYER_TYPE_NONE
+ * @see #LAYER_TYPE_HARDWARE
+ */
+ public static final int LAYER_TYPE_SOFTWARE = 1;
+
+ /**
+ * Indicates that the view has a hardware layer. A hardware layer is backed
+ * by a hardware specific texture (generally Frame Buffer Objects or FBO on
+ * OpenGL hardware) and causes the view to be rendered using Android's hardware
+ * rendering pipeline, but only if hardware acceleration is turned on for the
+ * view hierarchy. When hardware acceleration is turned off, hardware layers
+ * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.
+ *
+ * A hardware layer is useful to apply a specific color filter and/or
+ * blending mode and/or translucency to a view and all its children.
+ * A hardware layer can also be used to increase the rendering quality when
+ * rotation transformations are applied on a view. It can also be used to
+ * prevent potential clipping issues when applying 3D transforms on a view.
+ *
+ * @see #getLayerType()
+ * @see #setLayerType(int, android.graphics.Paint)
+ * @see #LAYER_TYPE_NONE
+ * @see #LAYER_TYPE_SOFTWARE
+ */
+ public static final int LAYER_TYPE_HARDWARE = 2;
+
+ @ViewDebug.ExportedProperty(category = "drawing")
+ int mLayerType = LAYER_TYPE_NONE;
+ Paint mLayerPaint;
+
/**
* Simple constructor to use when creating a view from code.
*
@@ -2489,6 +2557,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
case R.styleable.View_verticalScrollbarPosition:
mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT);
break;
+ case R.styleable.View_layerType:
+ setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null);
+ break;
}
}
@@ -5763,11 +5834,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
- * completely transparent and 1 means the view is completely opaque.
+ * Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
+ * completely transparent and 1 means the view is completely opaque.
+ *
+ * If this view overrides {@link #onSetAlpha(int)} to return true, then this view is
+ * responsible for applying the opacity itself. Otherwise, calling this method is
+ * equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
+ * setting a hardware layer.
*
* @param alpha The opacity of the view.
*
+ * @see #setLayerType(int, android.graphics.Paint)
+ *
* @attr ref android.R.styleable#View_alpha
*/
public void setAlpha(float alpha) {
@@ -7746,6 +7824,88 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE;
}
+ /**
+ * Specifies the type of layer backing this view. The layer can be
+ * {@link #LAYER_TYPE_NONE disabled}, {@link #LAYER_TYPE_SOFTWARE software} or
+ * {@link #LAYER_TYPE_HARDWARE hardware}.
+ *
+ * A layer is associated with an optional {@link android.graphics.Paint}
+ * instance that controls how the layer is composed on screen. The following
+ * properties of the paint are taken into account when composing the layer:
+ *
+ * - {@link android.graphics.Paint#getAlpha() Translucency (alpha)}
+ * - {@link android.graphics.Paint#getXfermode() Blending mode}
+ * - {@link android.graphics.Paint#getColorFilter() Color filter}
+ *
+ *
+ * If this view has an alpha value set to < 1.0 by calling
+ * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
+ * this view's alpha value. Calling {@link #setAlpha(float)} is therefore
+ * equivalent to setting a hardware layer on this view and providing a paint with
+ * the desired alpha value.
+ *
+ *
Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
+ * {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
+ * for more information on when and how to use layers.
+ *
+ * @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}
+ *
+ * @see #getLayerType()
+ * @see #LAYER_TYPE_NONE
+ * @see #LAYER_TYPE_SOFTWARE
+ * @see #LAYER_TYPE_HARDWARE
+ * @see #setAlpha(float)
+ *
+ * @attr ref android.R.styleable#View_layerType
+ */
+ public void setLayerType(int layerType, Paint paint) {
+ if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) {
+ throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, "
+ + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
+ }
+
+ // Destroy any previous software drawing cache if needed
+ if (mLayerType == LAYER_TYPE_SOFTWARE && layerType != LAYER_TYPE_SOFTWARE) {
+ if (mDrawingCache != null) {
+ mDrawingCache.recycle();
+ mDrawingCache = null;
+ }
+
+ if (mUnscaledDrawingCache != null) {
+ mUnscaledDrawingCache.recycle();
+ mUnscaledDrawingCache = null;
+ }
+ }
+
+ mLayerType = layerType;
+ mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint;
+
+ invalidate();
+ }
+
+ /**
+ * Indicates what type of layer is currently associated with this view. By default
+ * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}.
+ * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)}
+ * for more information on the different types of layers.
+ *
+ * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
+ * {@link #LAYER_TYPE_HARDWARE}
+ *
+ * @see #setLayerType(int, android.graphics.Paint)
+ * @see #LAYER_TYPE_NONE
+ * @see #LAYER_TYPE_SOFTWARE
+ * @see #LAYER_TYPE_HARDWARE
+ */
+ public int getLayerType() {
+ return mLayerType;
+ }
+
/**
* Enables or disables the drawing cache. When the drawing cache is enabled, the next call
* to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a
@@ -7753,12 +7913,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* the cache is enabled. To benefit from the cache, you must request the drawing cache by
* calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not
* null.
+ *
+ * Enabling the drawing cache is similar to
+ * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware
+ * acceleration is turned off. When hardware acceleration is turned on enabling the
+ * drawing cache has either no effect or the cache used at drawing time is not a bitmap.
+ * This API can however be used to manually generate a bitmap copy of this view.
*
* @param enabled true to enable the drawing cache, false otherwise
*
* @see #isDrawingCacheEnabled()
* @see #getDrawingCache()
* @see #buildDrawingCache()
+ * @see #setLayerType(int, android.graphics.Paint)
*/
public void setDrawingCacheEnabled(boolean enabled) {
setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
@@ -8077,7 +8244,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
canvas.translate(-mScrollX, -mScrollY);
mPrivateFlags |= DRAWN;
- if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated) {
+ if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
+ mLayerType != LAYER_TYPE_NONE) {
mPrivateFlags |= DRAWING_CACHE_VALID;
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 513844264051f..82cf75337a56b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2175,11 +2175,15 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
boolean concatMatrix = false;
boolean scalingRequired = false;
- boolean caching = false;
+ boolean caching;
+ final int layerType = child.getLayerType();
+
if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
(flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
caching = true;
if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
+ } else {
+ caching = layerType != LAYER_TYPE_NONE;
}
if (a != null) {
@@ -2270,9 +2274,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
Bitmap cache = null;
if (caching) {
if (!canvas.isHardwareAccelerated()) {
+ if (layerType != LAYER_TYPE_NONE) {
+ child.buildDrawingCache(true);
+ }
cache = child.getDrawingCache(true);
} else {
- displayList = child.getDisplayList();
+ if (layerType == LAYER_TYPE_SOFTWARE) {
+ child.buildDrawingCache(true);
+ cache = child.getDrawingCache(true);
+ } else {
+ displayList = child.getDisplayList();
+ }
}
}
@@ -2290,6 +2302,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
canvas.scale(scale, scale);
}
}
+
+ boolean layerSaved = false;
if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
if (transformToApply != null || !childHasIdentityMatrix) {
@@ -2331,12 +2345,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final int multipliedAlpha = (int) (255 * alpha);
if (!child.onSetAlpha(multipliedAlpha)) {
int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
+ if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN ||
+ layerType != LAYER_TYPE_NONE) {
layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
}
- canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct, multipliedAlpha,
- layerFlags);
+ if (layerType != LAYER_TYPE_NONE && child.mLayerPaint != null) {
+ child.mLayerPaint.setAlpha(multipliedAlpha);
+ canvas.saveLayer(sx, sy, sx + cr - cl, sy + cb - ct,
+ child.mLayerPaint, layerFlags);
+ } else {
+ canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct,
+ multipliedAlpha, layerFlags);
+ }
+ layerSaved = true;
} else {
+ // Alpha is handled by the child directly, clobber the layer's alpha
+ if (layerType != LAYER_TYPE_NONE && child.mLayerPaint != null) {
+ child.mLayerPaint.setAlpha(255);
+ }
child.mPrivateFlags |= ALPHA_SET;
}
}
@@ -2359,6 +2385,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
if (hasNoCache) {
+ if (!layerSaved && layerType == LAYER_TYPE_HARDWARE) {
+ canvas.saveLayer(sx, sy, sx + cr - cl, sy + cb - ct, child.mLayerPaint,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ }
if (!hasDisplayList) {
// Fast path for layouts with no backgrounds
if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
@@ -2376,13 +2406,22 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
} else if (cache != null) {
child.mPrivateFlags &= ~DIRTY_MASK;
- final Paint cachePaint = mCachePaint;
- if (alpha < 1.0f) {
- cachePaint.setAlpha((int) (alpha * 255));
- mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
- } else if ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
- cachePaint.setAlpha(255);
- mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
+ Paint cachePaint;
+
+ if (layerType == LAYER_TYPE_NONE || child.mLayerPaint == null) {
+ cachePaint = mCachePaint;
+ if (alpha < 1.0f) {
+ cachePaint.setAlpha((int) (alpha * 255));
+ mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
+ } else if ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
+ cachePaint.setAlpha(255);
+ mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
+ }
+ } else {
+ cachePaint = child.mLayerPaint;
+ if (alpha < 1.0f) {
+ cachePaint.setAlpha((int) (alpha * 255));
+ }
}
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 14c8f46e7fec9..f909bd6385118 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1784,6 +1784,22 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index a780183a1c335..7d54d3b3255df 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -26,6 +26,7 @@
#include
#include "Rect.h"
+#include "SkiaColorFilter.h"
namespace android {
namespace uirenderer {
@@ -93,6 +94,11 @@ struct Layer {
* have been drawn.
*/
Region region;
+
+ /**
+ * Color filter used to draw this layer. Optional.
+ */
+ SkiaColorFilter* colorFilter;
}; // struct Layer
}; // namespace uirenderer
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 9ce0359140bb2..ec186a481e7c0 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -102,6 +102,7 @@ Layer* LayerCache::get(const uint32_t width, const uint32_t height) {
layer->blend = true;
layer->empty = true;
layer->fbo = 0;
+ layer->colorFilter = NULL;
glGenTextures(1, &layer->texture);
glBindTexture(GL_TEXTURE_2D, layer->texture);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index eec8d8c73fee6..9613c5f6b8ffe 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -406,6 +406,7 @@ bool OpenGLRenderer::createLayer(sp snapshot, float left, float top,
layer->layer.set(bounds);
layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->height),
bounds.getWidth() / float(layer->width), 0.0f);
+ layer->colorFilter = mColorFilter;
// Save the layer in the snapshot
snapshot->flags |= Snapshot::kFlagIsLayer;
@@ -459,7 +460,6 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, sp sna
snapshot->flags |= Snapshot::kFlagIsFboLayer;
snapshot->fbo = layer->fbo;
snapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
- //snapshot->resetClip(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
snapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
snapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
snapshot->height = bounds.getHeight();
@@ -544,7 +544,13 @@ void OpenGLRenderer::composeLayer(sp current, sp previous) {
// drawing only the dirty region
if (fboLayer) {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom, *previous->transform);
+ if (layer->colorFilter) {
+ setupColorFilter(layer->colorFilter);
+ }
composeLayerRegion(layer, rect);
+ if (layer->colorFilter) {
+ resetColorFilter();
+ }
} else {
dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
composeLayerRect(layer, rect, true);
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index c14988c91c8ae..0fdc030b88990 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -24,6 +24,15 @@
android:label="HwUi"
android:hardwareAccelerated="true">
+
+
+
+
+
+
+
diff --git a/tests/HwAccelerationTest/res/layout/_advanced_blend.xml b/tests/HwAccelerationTest/res/layout/_advanced_blend.xml
index 6efdd7345b69d..5b6fd3c2624a0 100644
--- a/tests/HwAccelerationTest/res/layout/_advanced_blend.xml
+++ b/tests/HwAccelerationTest/res/layout/_advanced_blend.xml
@@ -1,6 +1,19 @@
+
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
diff --git a/tests/HwAccelerationTest/res/layout/_advanced_gradient.xml b/tests/HwAccelerationTest/res/layout/_advanced_gradient.xml
index dd937f9b5676e..5e32ed2ec7cbb 100644
--- a/tests/HwAccelerationTest/res/layout/_advanced_gradient.xml
+++ b/tests/HwAccelerationTest/res/layout/_advanced_gradient.xml
@@ -1,6 +1,19 @@
+
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
diff --git a/tests/HwAccelerationTest/res/layout/_layers.xml b/tests/HwAccelerationTest/res/layout/_layers.xml
index c2b186d985ced..25c76ac710cfd 100644
--- a/tests/HwAccelerationTest/res/layout/_layers.xml
+++ b/tests/HwAccelerationTest/res/layout/_layers.xml
@@ -1,6 +1,20 @@
+
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
diff --git a/tests/HwAccelerationTest/res/layout/_lines.xml b/tests/HwAccelerationTest/res/layout/_lines.xml
index 00f255682932b..c24dc25af9ac4 100644
--- a/tests/HwAccelerationTest/res/layout/_lines.xml
+++ b/tests/HwAccelerationTest/res/layout/_lines.xml
@@ -1,6 +1,20 @@
+
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
diff --git a/tests/HwAccelerationTest/res/layout/_newlayers.xml b/tests/HwAccelerationTest/res/layout/_newlayers.xml
index 062a2e1a2e16d..5c37e371aeffe 100644
--- a/tests/HwAccelerationTest/res/layout/_newlayers.xml
+++ b/tests/HwAccelerationTest/res/layout/_newlayers.xml
@@ -1,6 +1,20 @@
+
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
diff --git a/tests/HwAccelerationTest/res/layout/_paths.xml b/tests/HwAccelerationTest/res/layout/_paths.xml
index b0534826d5652..34baf8474b6cd 100644
--- a/tests/HwAccelerationTest/res/layout/_paths.xml
+++ b/tests/HwAccelerationTest/res/layout/_paths.xml
@@ -1,6 +1,19 @@
+
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
diff --git a/tests/HwAccelerationTest/res/layout/_shaders.xml b/tests/HwAccelerationTest/res/layout/_shaders.xml
index dcb42fba929a6..070ac1291f2c8 100644
--- a/tests/HwAccelerationTest/res/layout/_shaders.xml
+++ b/tests/HwAccelerationTest/res/layout/_shaders.xml
@@ -1,6 +1,20 @@
+
-
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
diff --git a/tests/HwAccelerationTest/res/layout/view_layers.xml b/tests/HwAccelerationTest/res/layout/view_layers.xml
new file mode 100644
index 0000000000000..e0cdc78d2ae99
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/view_layers.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java
new file mode 100644
index 0000000000000..359447d069959
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewLayersActivity.java
@@ -0,0 +1,158 @@
+/*
+ * 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.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class ViewLayersActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.view_layers);
+
+ setupList(R.id.list1);
+ setupList(R.id.list2);
+ setupList(R.id.list3);
+
+ getWindow().getDecorView().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ final View leftList = findViewById(R.id.list1);
+ final View middleList = findViewById(R.id.list2);
+ final View rightList = findViewById(R.id.list3);
+
+ final ObjectAnimator moveRight = ObjectAnimator.ofFloat(leftList,
+ "x", 0, rightList.getLeft());
+ moveRight.setDuration(1500);
+ moveRight.setRepeatCount(ObjectAnimator.INFINITE);
+ moveRight.setRepeatMode(ObjectAnimator.REVERSE);
+
+ final ObjectAnimator moveLeft = ObjectAnimator.ofFloat(rightList,
+ "x", rightList.getLeft(), 0);
+ moveLeft.setDuration(1500);
+ moveLeft.setRepeatCount(ObjectAnimator.INFINITE);
+ moveLeft.setRepeatMode(ObjectAnimator.REVERSE);
+
+ final ObjectAnimator rotate = ObjectAnimator.ofFloat(middleList,
+ "rotationY", 0, 360);
+ rotate.setDuration(3000);
+ rotate.setRepeatCount(ObjectAnimator.INFINITE);
+ rotate.setRepeatMode(ObjectAnimator.REVERSE);
+
+ Paint p = new Paint();
+ p.setColorFilter(new PorterDuffColorFilter(0xffff0000, PorterDuff.Mode.MULTIPLY));
+
+ Paint p2 = new Paint();
+ p2.setAlpha(127);
+
+ Paint p3 = new Paint();
+ p3.setColorFilter(new PorterDuffColorFilter(0xff00ff00, PorterDuff.Mode.MULTIPLY));
+
+ leftList.setLayerType(View.LAYER_TYPE_SOFTWARE, p);
+ leftList.setAlpha(0.5f);
+ middleList.setLayerType(View.LAYER_TYPE_HARDWARE, p3);
+ middleList.setAlpha(0.5f);
+ rightList.setLayerType(View.LAYER_TYPE_SOFTWARE, p2);
+
+ moveRight.start();
+ moveLeft.start();
+ rotate.start();
+ }
+ }, 2000);
+ }
+
+ private void setupList(int listId) {
+ final ListView list = (ListView) findViewById(listId);
+ list.setAdapter(new SimpleListAdapter(this));
+ }
+
+ private static class SimpleListAdapter extends ArrayAdapter {
+ public SimpleListAdapter(Context context) {
+ super(context, android.R.layout.simple_list_item_1, DATA_LIST);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView v = (TextView) super.getView(position, convertView, parent);
+ final Resources r = getContext().getResources();
+ final DisplayMetrics metrics = r.getDisplayMetrics();
+ v.setCompoundDrawablePadding((int) (6 * metrics.density + 0.5f));
+ v.setCompoundDrawablesWithIntrinsicBounds(r.getDrawable(R.drawable.icon),
+ null, null, null);
+ return v;
+ }
+ }
+
+ private static final String[] DATA_LIST = {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
+ "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria",
+ "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}