summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chet Haase <chet@google.com> 2012-03-21 18:54:18 -0700
committer Chet Haase <chet@google.com> 2012-04-03 14:02:17 -0700
commitdb8c9a6a4d9bf8c39f834b25611926caf21380f6 (patch)
tree5a1ef2e49ea05c5a28477fcf8525ca66e8e31890
parentb3fa3960a03ef553e58bf1add88029a6c072c6b6 (diff)
Optimization of alpha with DisplayList properties
Some views (such as ImageView and TextView) handle non-opaque alpha values directly. This was originally an optimization, but we can handle it faster in many cases without this optimization when DisplayList properties are enabled. Basically, if a view has non-overlapping rendering, we set the alpha value directly on the renderer (the equivalent of setting it on the Paint object) and draw each primitive with that alpha value. Doing it this way avoids re-creating DisplayLists while getting the same speedup that onSetAlpha() used to get pre-DisplayList properties. Change-Id: I0f7827f075d3b35093a882d4adbb300a1063c288
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/view/DisplayList.java9
-rw-r--r--core/java/android/view/GLES20DisplayList.java11
-rw-r--r--core/java/android/view/HardwareRenderer.java6
-rw-r--r--core/java/android/view/View.java44
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java13
-rw-r--r--core/java/android/widget/ImageView.java11
-rw-r--r--core/java/android/widget/TextView.java12
-rw-r--r--core/jni/android_view_GLES20DisplayList.cpp7
-rw-r--r--libs/hwui/DisplayListRenderer.cpp28
-rw-r--r--libs/hwui/DisplayListRenderer.h5
-rw-r--r--libs/hwui/OpenGLRenderer.cpp2
-rw-r--r--libs/hwui/OpenGLRenderer.h4
-rw-r--r--libs/hwui/Snapshot.cpp4
-rw-r--r--libs/hwui/Snapshot.h11
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/res/layout/view_properties.xml81
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java145
18 files changed, 368 insertions, 35 deletions
diff --git a/api/current.txt b/api/current.txt
index eba8a2c22910..ea93c62d83d9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23371,6 +23371,7 @@ package android.view {
method public boolean hasFocus();
method public boolean hasFocusable();
method public boolean hasOnClickListeners();
+ method public boolean hasOverlappingRendering();
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 33631b774d9b..fba73fbdd522 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -149,6 +149,15 @@ public abstract class DisplayList {
public abstract void setAlpha(float alpha);
/**
+ * Sets whether the DisplayList renders content which overlaps. Non-overlapping rendering
+ * can use a fast path for alpha that avoids rendering to an offscreen buffer.
+ *
+ * @param hasOverlappingRendering
+ * @see android.view.View#hasOverlappingRendering()
+ */
+ public abstract void setHasOverlappingRendering(boolean hasOverlappingRendering);
+
+ /**
* Sets the translationX value for the DisplayList
*
* @param translationX The translationX value of the DisplayList
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index bc3bce0cfdaf..f3618eb67302 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -147,6 +147,15 @@ class GLES20DisplayList extends DisplayList {
}
@Override
+ public void setHasOverlappingRendering(boolean hasOverlappingRendering) {
+ try {
+ nSetHasOverlappingRendering(getNativeDisplayList(), hasOverlappingRendering);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
public void setTranslationX(float translationX) {
try {
nSetTranslationX(getNativeDisplayList(), translationX);
@@ -335,6 +344,8 @@ class GLES20DisplayList extends DisplayList {
private static native void nSetClipChildren(int displayList, boolean clipChildren);
private static native void nSetApplicationScale(int displayList, float scale);
private static native void nSetAlpha(int displayList, float alpha);
+ private static native void nSetHasOverlappingRendering(int displayList,
+ boolean hasOverlappingRendering);
private static native void nSetTranslationX(int displayList, float translationX);
private static native void nSetTranslationY(int displayList, float translationY);
private static native void nSetRotation(int displayList, float rotation);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b100a0c50113..9ef262144d66 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -134,7 +134,7 @@ public abstract class HardwareRenderer {
/**
* Number of frames to profile.
*/
- private static final int PROFILE_MAX_FRAMES = 64;
+ private static final int PROFILE_MAX_FRAMES = 120;
/**
* Number of floats per profiled frame.
@@ -1046,10 +1046,6 @@ public abstract class HardwareRenderer {
Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took " +
total + "ms");
}
- if (View.USE_DISPLAY_LIST_PROPERTIES) {
- Log.d("DLProperties", "getDisplayList():\t" +
- mProfileData[mProfileCurrentFrame]);
- }
}
if (displayList != null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 69d7655f6aa7..cecb445baa24 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2830,19 +2830,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
private boolean mSendingHoverAccessibilityEvents;
/**
- * Delegate for injecting accessiblity functionality.
- */
- AccessibilityDelegate mAccessibilityDelegate;
-
- /**
- * Consistency verifier for debugging purposes.
- * @hide
- */
- protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
- InputEventConsistencyVerifier.isInstrumentationEnabled() ?
- new InputEventConsistencyVerifier(this, 0) : null;
-
- /**
* Simple constructor to use when creating a view from code.
*
* @param context The Context the view is running in, through which it can
@@ -2863,6 +2850,19 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
+ * Delegate for injecting accessiblity functionality.
+ */
+ AccessibilityDelegate mAccessibilityDelegate;
+
+ /**
+ * Consistency verifier for debugging purposes.
+ * @hide
+ */
+ protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
+ InputEventConsistencyVerifier.isInstrumentationEnabled() ?
+ new InputEventConsistencyVerifier(this, 0) : null;
+
+ /**
* Constructor that is called when inflating a view from XML. This is called
* when a view is being constructed from an XML file, supplying attributes
* that were specified in the XML file. This version uses a default style of
@@ -7855,6 +7855,23 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
+ * Returns whether this View has content which overlaps. This function, intended to be
+ * overridden by specific View types, is an optimization when alpha is set on a view. If
+ * rendering overlaps in a view with alpha < 1, that view is drawn to an offscreen buffer
+ * and then composited it into place, which can be expensive. If the view has no overlapping
+ * rendering, the view can draw each primitive with the appropriate alpha value directly.
+ * An example of overlapping rendering is a TextView with a background image, such as a
+ * Button. An example of non-overlapping rendering is a TextView with no background, or
+ * an ImageView with only the foreground image. The default implementation returns true;
+ * subclasses should override if they have cases which can be optimized.
+ *
+ * @return true if the content in this view might overlap, false otherwise.
+ */
+ public boolean hasOverlappingRendering() {
+ return true;
+ }
+
+ /**
* <p>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.</p>
*
@@ -11525,6 +11542,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
void setDisplayListProperties(DisplayList displayList) {
if (USE_DISPLAY_LIST_PROPERTIES && displayList != null) {
displayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+ displayList.setHasOverlappingRendering(hasOverlappingRendering());
if (mParent instanceof ViewGroup) {
displayList.setClipChildren(
(((ViewGroup)mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 623b56713394..3626aba93eed 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -834,40 +834,49 @@ public class ViewPropertyAnimator {
*/
private void setValue(int propertyConstant, float value) {
final View.TransformationInfo info = mView.mTransformationInfo;
+ DisplayList displayList = View.USE_DISPLAY_LIST_PROPERTIES ? mView.mDisplayList : null;
switch (propertyConstant) {
case TRANSLATION_X:
info.mTranslationX = value;
+ if (displayList != null) displayList.setTranslationX(value);
break;
case TRANSLATION_Y:
info.mTranslationY = value;
+ if (displayList != null) displayList.setTranslationY(value);
break;
case ROTATION:
info.mRotation = value;
+ if (displayList != null) displayList.setRotation(value);
break;
case ROTATION_X:
info.mRotationX = value;
+ if (displayList != null) displayList.setRotationX(value);
break;
case ROTATION_Y:
info.mRotationY = value;
+ if (displayList != null) displayList.setRotationY(value);
break;
case SCALE_X:
info.mScaleX = value;
+ if (displayList != null) displayList.setScaleX(value);
break;
case SCALE_Y:
info.mScaleY = value;
+ if (displayList != null) displayList.setScaleY(value);
break;
case X:
info.mTranslationX = value - mView.mLeft;
+ if (displayList != null) displayList.setTranslationX(value - mView.mLeft);
break;
case Y:
info.mTranslationY = value - mView.mTop;
+ if (displayList != null) displayList.setTranslationY(value - mView.mTop);
break;
case ALPHA:
info.mAlpha = value;
+ if (displayList != null) displayList.setAlpha(value);
break;
}
- // TODO: optimize to set only the properties that have changed
- mView.setDisplayListProperties();
}
/**
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b1a75e1c3d10..91e2e4976257 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -201,7 +201,7 @@ public class ImageView extends View {
@Override
protected boolean onSetAlpha(int alpha) {
- if (getBackground() == null) {
+ if (!USE_DISPLAY_LIST_PROPERTIES && getBackground() == null) {
int scale = alpha + (alpha >> 7);
if (mViewAlphaScale != scale) {
mViewAlphaScale = scale;
@@ -214,6 +214,15 @@ public class ImageView extends View {
}
@Override
+ public boolean hasOverlappingRendering() {
+ if (!USE_DISPLAY_LIST_PROPERTIES) {
+ return super.hasOverlappingRendering();
+ } else {
+ return (getBackground() != null);
+ }
+ }
+
+ @Override
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
super.onPopulateAccessibilityEvent(event);
CharSequence contentDescription = getContentDescription();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2a81f080eeb8..d2a175565050 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4268,7 +4268,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
protected boolean onSetAlpha(int alpha) {
// Alpha is supported if and only if the drawing can be done in one pass.
// TODO text with spans with a background color currently do not respect this alpha.
- if (getBackground() == null) {
+ if (!USE_DISPLAY_LIST_PROPERTIES &&
+ (getBackground() != null || mText instanceof Spannable || hasSelection())) {
if (mCurrentAlpha != alpha) {
mCurrentAlpha = alpha;
final Drawables dr = mDrawables;
@@ -4292,6 +4293,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ if (!USE_DISPLAY_LIST_PROPERTIES) {
+ return super.hasOverlappingRendering();
+ } else {
+ return (getBackground() != null || mText instanceof Spannable || hasSelection());
+ }
+ }
+
/**
* When a TextView is used to display a useful piece of information to the user (such as a
* contact's address), it should be made selectable, so that the user can select and copy this
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
index 60fb6d45d5fa..b307a2f9d8f9 100644
--- a/core/jni/android_view_GLES20DisplayList.cpp
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -65,6 +65,11 @@ static void android_view_GLES20DisplayList_setAlpha(JNIEnv* env,
displayList->setAlpha(alpha);
}
+static void android_view_GLES20DisplayList_setHasOverlappingRendering(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, bool hasOverlappingRendering) {
+ displayList->setHasOverlappingRendering(hasOverlappingRendering);
+}
+
static void android_view_GLES20DisplayList_setTranslationX(JNIEnv* env,
jobject clazz, DisplayList* displayList, float tx) {
displayList->setTranslationX(tx);
@@ -185,6 +190,8 @@ static JNINativeMethod gMethods[] = {
{ "nSetAnimationMatrix", "(II)V", (void*) android_view_GLES20DisplayList_setAnimationMatrix },
{ "nSetClipChildren", "(IZ)V", (void*) android_view_GLES20DisplayList_setClipChildren },
{ "nSetAlpha", "(IF)V", (void*) android_view_GLES20DisplayList_setAlpha },
+ { "nSetHasOverlappingRendering", "(IZ)V",
+ (void*) android_view_GLES20DisplayList_setHasOverlappingRendering },
{ "nSetTranslationX", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationX },
{ "nSetTranslationY", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationY },
{ "nSetRotation", "(IF)V", (void*) android_view_GLES20DisplayList_setRotation },
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f37bfd2f9c12..9f2bacdef24d 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -112,6 +112,7 @@ void DisplayList::initProperties() {
mClipChildren = true;
mAlpha = 1;
mMultipliedAlpha = 255;
+ mHasOverlappingRendering = true;
mTranslationX = 0;
mTranslationY = 0;
mRotation = 0;
@@ -772,18 +773,23 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t width, ui
}
}
if (mAlpha < 1 && !mCaching) {
- // TODO: should be able to store the size of a DL at record time and not
- // have to pass it into this call. In fact, this information might be in the
- // location/size info that we store with the new native transform data.
- int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
- if (mClipChildren) {
- flags |= SkCanvas::kClipToLayer_SaveFlag;
+ if (!mHasOverlappingRendering) {
+ DISPLAY_LIST_LOGD("%s%s %.2f", indent, "SetAlpha", mAlpha);
+ renderer.setAlpha(mAlpha);
+ } else {
+ // TODO: should be able to store the size of a DL at record time and not
+ // have to pass it into this call. In fact, this information might be in the
+ // location/size info that we store with the new native transform data.
+ int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+ if (mClipChildren) {
+ flags |= SkCanvas::kClipToLayer_SaveFlag;
+ }
+ DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+ (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
+ mMultipliedAlpha, flags);
+ renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
+ mMultipliedAlpha, flags);
}
- DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
- (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
- mMultipliedAlpha, flags);
- renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
- mMultipliedAlpha, flags);
}
if (mClipChildren) {
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 38b0a6d6f173..fe0c94d9a2e3 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -181,6 +181,10 @@ public:
}
}
+ void setHasOverlappingRendering(bool hasOverlappingRendering) {
+ mHasOverlappingRendering = hasOverlappingRendering;
+ }
+
void setTranslationX(float translationX) {
if (translationX != mTranslationX) {
mTranslationX = translationX;
@@ -496,6 +500,7 @@ private:
bool mClipChildren;
float mAlpha;
int mMultipliedAlpha;
+ bool mHasOverlappingRendering;
float mTranslationX, mTranslationY;
float mRotation, mRotationX, mRotationY;
float mScaleX, mScaleY;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 115787c87ebc..ec9b56b4ca2d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1101,6 +1101,7 @@ void OpenGLRenderer::setupDrawColor(int color) {
void OpenGLRenderer::setupDrawColor(int color, int alpha) {
mColorA = alpha / 255.0f;
+ mColorA *= mSnapshot->alpha;
// Second divide of a by 255 is an optimization, allowing us to simply multiply
// the rgb values by a instead of also dividing by 255
const float a = mColorA / 255.0f;
@@ -2800,6 +2801,7 @@ void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mod
*mode = SkXfermode::kSrcOver_Mode;
*alpha = 255;
}
+ *alpha *= mSnapshot->alpha;
}
SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b6519047eead..ab137ccec98f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -85,6 +85,10 @@ public:
virtual int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags);
+ virtual void setAlpha(float alpha) {
+ mSnapshot->alpha = alpha;
+ }
+
virtual void translate(float dx, float dy);
virtual void rotate(float degrees);
virtual void scale(float sx, float sy);
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index de2c6745cc97..5d5961a14004 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -26,7 +26,7 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
- invisible(false), empty(false) {
+ invisible(false), empty(false), alpha(1.0f) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
@@ -41,7 +41,7 @@ Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
flags(0), previous(s), layer(NULL), fbo(s->fbo),
invisible(s->invisible), empty(false),
- viewport(s->viewport), height(s->height) {
+ viewport(s->viewport), height(s->height), alpha(s->alpha) {
clipRegion = NULL;
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index b2bc879760e4..30b03fc33db6 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -208,6 +208,17 @@ public:
*/
Region* region;
+ /**
+ * Current alpha value. This value is 1 by default, but may be set by a DisplayList which
+ * has translucent rendering in a non-overlapping View. This value will be used by
+ * the renderer to set the alpha in the current color being used for ensuing drawing
+ * operations. The value is inherited by child snapshots because the same value should
+ * be applied to descendents of the current DisplayList (for example, a TextView contains
+ * the base alpha value which should be applied to the child DisplayLists used for drawing
+ * the actual text).
+ */
+ float alpha;
+
private:
void ensureClipRegion();
void copyClipRectFromRegion();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index f4c0841d694a..ceda61076ba2 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -657,5 +657,14 @@
</intent-filter>
</activity>
+ <activity
+ android:name="ViewPropertyAlphaActivity"
+ android:label="_ViewPropAlpha">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
</application>
</manifest>
diff --git a/tests/HwAccelerationTest/res/layout/view_properties.xml b/tests/HwAccelerationTest/res/layout/view_properties.xml
new file mode 100644
index 000000000000..d7ed8192b3c4
--- /dev/null
+++ b/tests/HwAccelerationTest/res/layout/view_properties.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/container">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Invalidate"
+ android:id="@+id/invalidateButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button"
+ android:id="@+id/button"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Some text"
+ android:id="@+id/textview"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/spantext"/>
+ <EditText
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Edit text"
+ android:id="@+id/edittext"/>
+ <EditText
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Selected text"
+ android:id="@+id/selectedtext"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Some text"
+ android:background="#00ff00"
+ android:id="@+id/textviewbackground"/>
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/icon"
+ android:id="@+id/imageview"/>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:id="@+id/layout">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Some text"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Some text"
+ android:background="#00ff00"/>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java
new file mode 100644
index 000000000000..738801d8b285
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ViewPropertyAlphaActivity.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012 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.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.style.BackgroundColorSpan;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.ImageSpan;
+import android.text.style.SuggestionSpan;
+import android.text.style.UnderlineSpan;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class ViewPropertyAlphaActivity extends Activity {
+
+ MyView myViewAlphaDefault, myViewAlphaHandled;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.view_properties);
+
+ getWindow().getDecorView().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ startAnim(R.id.button);
+ startAnim(R.id.textview);
+ startAnim(R.id.spantext);
+ startAnim(R.id.edittext);
+ startAnim(R.id.selectedtext);
+ startAnim(R.id.textviewbackground);
+ startAnim(R.id.layout);
+ startAnim(R.id.imageview);
+ startAnim(myViewAlphaDefault);
+ startAnim(myViewAlphaHandled);
+ EditText selectedText = (EditText) findViewById(R.id.selectedtext);
+ selectedText.setSelection(3, 8);
+ }
+ }, 2000);
+
+ Button invalidator = (Button) findViewById(R.id.invalidateButton);
+ invalidator.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ findViewById(R.id.textview).invalidate();
+ findViewById(R.id.spantext).invalidate();
+ }
+ });
+
+ TextView textView = (TextView) findViewById(R.id.spantext);
+ if (textView != null) {
+ SpannableStringBuilder text =
+ new SpannableStringBuilder("Now this is a short text message with spans");
+
+ text.setSpan(new BackgroundColorSpan(Color.RED), 0, 3,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new ForegroundColorSpan(Color.BLUE), 4, 9,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new SuggestionSpan(this, new String[]{"longer"}, 3), 11, 16,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new UnderlineSpan(), 17, 20,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ text.setSpan(new ImageSpan(this, R.drawable.icon), 21, 22,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ textView.setText(text);
+ }
+
+ LinearLayout container = (LinearLayout) findViewById(R.id.container);
+ myViewAlphaDefault = new MyView(this, false);
+ myViewAlphaDefault.setLayoutParams(new LinearLayout.LayoutParams(75, 75));
+ container.addView(myViewAlphaDefault);
+ myViewAlphaHandled = new MyView(this, true);
+ myViewAlphaHandled.setLayoutParams(new LinearLayout.LayoutParams(75, 75));
+ container.addView(myViewAlphaHandled);
+ }
+
+ private void startAnim(View target) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(target, View.ALPHA, 0);
+ anim.setRepeatCount(ValueAnimator.INFINITE);
+ anim.setRepeatMode(ValueAnimator.REVERSE);
+ anim.setDuration(1000);
+ anim.start();
+ }
+ private void startAnim(int id) {
+ startAnim(findViewById(id));
+ }
+
+ private static class MyView extends View {
+ private int mMyAlpha = 255;
+ private boolean mHandleAlpha;
+ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ private MyView(Context context, boolean handleAlpha) {
+ super(context);
+ mHandleAlpha = handleAlpha;
+ mPaint.setColor(Color.RED);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mHandleAlpha) {
+ mPaint.setAlpha(mMyAlpha);
+ }
+ canvas.drawCircle(30, 30, 30, mPaint);
+ }
+
+ @Override
+ protected boolean onSetAlpha(int alpha) {
+ if (mHandleAlpha) {
+ mMyAlpha = alpha;
+ return true;
+ }
+ return super.onSetAlpha(alpha);
+ }
+ }
+
+}