summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChet Haase <chet@google.com>2012-04-03 15:40:54 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-04-03 15:40:54 -0700
commit21aec19d3041fe040004dd32eef0cfd1bafd6fb6 (patch)
treea537409db7054f2faa88b2661cbec9a113bcb7e6
parent66ac90276a07b63ad74761d0bd0f1a7218babfbf (diff)
parentdb8c9a6a4d9bf8c39f834b25611926caf21380f6 (diff)
downloadframeworks_base-21aec19d3041fe040004dd32eef0cfd1bafd6fb6.zip
frameworks_base-21aec19d3041fe040004dd32eef0cfd1bafd6fb6.tar.gz
frameworks_base-21aec19d3041fe040004dd32eef0cfd1bafd6fb6.tar.bz2
Merge "Optimization of alpha with DisplayList properties"
-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 05fca90..b08705e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23373,6 +23373,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 33631b7..fba73fbd 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 bc3bce0..f3618eb 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 b100a0c..9ef2621 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 a9421f0..c40a7d5 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>
*
@@ -11534,6 +11551,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 623b567..3626aba 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 b1a75e1..91e2e49 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 2a81f08..d2a1755 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 60fb6d4..b307a2f 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 f37bfd2..9f2bacd 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 38b0a6d..fe0c94d 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 115787c..ec9b56b 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 b651904..ab137cc 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 de2c674..5d5961a 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 b2bc879..30b03fc 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 f4c0841..ceda610 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 0000000..d7ed819
--- /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 0000000..738801d
--- /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);
+ }
+ }
+
+}