Added native functionality to create a color layer.

Added a new layer that can draw a specified color and specified
alpha. This will replace creating a dim layer and allow any colors,
not just black, to be set for this layer.

Test: Added tests to Transaction_test.cpp to test with a color
      and a color layer with alpha.

Change-Id: I00a38d1bbc01093026f088c3347454281bdc2b8c
diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp
index 57ddde0..d3dc16d 100644
--- a/libs/gui/LayerDebugInfo.cpp
+++ b/libs/gui/LayerDebugInfo.cpp
@@ -43,7 +43,10 @@
     RETURN_ON_ERROR(parcel->writeInt32(mHeight));
     RETURN_ON_ERROR(parcel->write(mCrop));
     RETURN_ON_ERROR(parcel->write(mFinalCrop));
-    RETURN_ON_ERROR(parcel->writeFloat(mAlpha));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.r));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.g));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.b));
+    RETURN_ON_ERROR(parcel->writeFloat(mColor.a));
     RETURN_ON_ERROR(parcel->writeUint32(mFlags));
     RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat));
     RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace)));
@@ -79,7 +82,14 @@
     RETURN_ON_ERROR(parcel->readInt32(&mHeight));
     RETURN_ON_ERROR(parcel->read(mCrop));
     RETURN_ON_ERROR(parcel->read(mFinalCrop));
-    RETURN_ON_ERROR(parcel->readFloat(&mAlpha));
+    mColor.r = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.g = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.b = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
+    mColor.a = parcel->readFloat();
+    RETURN_ON_ERROR(parcel->errorCheck());
     RETURN_ON_ERROR(parcel->readUint32(&mFlags));
     RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat));
     // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways?
@@ -116,8 +126,10 @@
     result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty);
     result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str());
     result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str());
-    result.appendFormat("alpha=%.3f, flags=0x%08x, ",
-            static_cast<double>(info.mAlpha), info.mFlags);
+    result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ",
+            static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g),
+            static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a),
+            info.mFlags);
     result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]",
             static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]),
             static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1]));
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 3418a49..fcee73f 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -46,6 +46,9 @@
     output.writeStrongBinder(IInterface::asBinder(barrierGbp));
     output.writeStrongBinder(relativeLayerHandle);
     output.writeStrongBinder(parentHandleForChild);
+    output.writeFloat(color.r);
+    output.writeFloat(color.g);
+    output.writeFloat(color.b);
     output.write(transparentRegion);
     return NO_ERROR;
 }
@@ -79,6 +82,9 @@
         interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
     relativeLayerHandle = input.readStrongBinder();
     parentHandleForChild = input.readStrongBinder();
+    color.r = input.readFloat();
+    color.g = input.readFloat();
+    color.b = input.readFloat();
     input.read(transparentRegion);
     return NO_ERROR;
 }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index be7b1d2..c5a4389 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -158,6 +158,8 @@
             const Region& transparentRegion);
     status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             float alpha);
+    status_t setColor(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+            const half3& color);
     status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             float dsdx, float dtdx, float dtdy, float dsdy);
     status_t setOrientation(int orientation);
@@ -402,6 +404,17 @@
     return NO_ERROR;
 }
 
+status_t Composer::setColor(const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, const half3& color) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= layer_state_t::eColorChanged;
+    s->color = color;
+    return NO_ERROR;
+}
+
 status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
         const sp<IBinder>& id, uint32_t layerStack) {
     Mutex::Autolock _l(mLock);
@@ -822,6 +835,10 @@
     return getComposer().setAlpha(this, id, alpha);
 }
 
+status_t SurfaceComposerClient::setColor(const sp<IBinder>& id, const half3& color) {
+    return getComposer().setColor(this, id, color);
+}
+
 status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) {
     return getComposer().setLayerStack(this, id, layerStack);
 }
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index d801d12..9e1d7b6 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -155,6 +155,11 @@
     if (err < 0) return err;
     return mClient->setAlpha(mHandle, alpha);
 }
+status_t SurfaceControl::setColor(const half3& color) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setColor(mHandle, color);
+}
 status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) {
     status_t err = validate();
     if (err < 0) return err;
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 2c613ea..d5bbef2 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -41,7 +41,7 @@
         eCursorWindow = 0x00002000,
 
         eFXSurfaceNormal = 0x00000000,
-        eFXSurfaceDim = 0x00020000,
+        eFXSurfaceColor = 0x00020000,
         eFXSurfaceMask = 0x000F0000,
     };
 
diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h
index 8453e04..92bd8c5 100644
--- a/libs/gui/include/gui/LayerDebugInfo.h
+++ b/libs/gui/include/gui/LayerDebugInfo.h
@@ -22,6 +22,7 @@
 #include <ui/Region.h>
 
 #include <string>
+#include <math/vec4.h>
 
 namespace android {
 
@@ -52,7 +53,7 @@
     int32_t mHeight = -1;
     Rect mCrop = Rect::INVALID_RECT;
     Rect mFinalCrop = Rect::INVALID_RECT;
-    float mAlpha = 0.f;
+    half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf);
     uint32_t mFlags = 0;
     PixelFormat mPixelFormat = PIXEL_FORMAT_NONE;
     android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index cf2ff5b..1718143 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -32,6 +32,7 @@
 
 #include <gui/CpuConsumer.h>
 #include <gui/SurfaceControl.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -149,6 +150,7 @@
     status_t    setRelativeLayer(const sp<IBinder>& id,
             const sp<IBinder>& relativeTo, int32_t layer);
     status_t    setAlpha(const sp<IBinder>& id, float alpha=1.0f);
+    status_t    setColor(const sp<IBinder>& id, const half3& color);
     status_t    setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy);
     status_t    setPosition(const sp<IBinder>& id, float x, float y);
     status_t    setSize(const sp<IBinder>& id, uint32_t w, uint32_t h);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index b506e00..e98e26a 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -29,6 +29,7 @@
 #include <ui/Region.h>
 
 #include <gui/ISurfaceComposerClient.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -90,6 +91,7 @@
     status_t    setFlags(uint32_t flags, uint32_t mask);
     status_t    setTransparentRegionHint(const Region& transparent);
     status_t    setAlpha(float alpha=1.0f);
+    status_t    setColor(const half3& color);
 
     // Experimentarily it appears that the matrix transforms the
     // on-screen rectangle and it's contents before the position is
diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/private/gui/LayerState.h
index 4ff2e5e..bd42634 100644
--- a/libs/gui/include/private/gui/LayerState.h
+++ b/libs/gui/include/private/gui/LayerState.h
@@ -25,6 +25,7 @@
 #include <ui/Region.h>
 #include <ui/Rect.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -60,7 +61,8 @@
         eReparentChildren           = 0x00002000,
         eDetachChildren             = 0x00004000,
         eRelativeLayerChanged       = 0x00008000,
-        eReparent                   = 0x00010000
+        eReparent                   = 0x00010000,
+        eColorChanged               = 0x00020000
     };
 
     layer_state_t()
@@ -110,6 +112,8 @@
 
             sp<IBinder>     parentHandleForChild;
 
+            half3           color;
+
             // non POD must be last. see write/read
             Region          transparentRegion;
 };
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 38529b6..1f4427a 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -14,7 +14,7 @@
     FrameTracker.cpp \
     GpuService.cpp \
     Layer.cpp \
-    LayerDim.cpp \
+    ColorLayer.cpp \
     LayerRejecter.cpp \
     LayerVector.cpp \
     MessageQueue.cpp \
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/ColorLayer.cpp
similarity index 79%
rename from services/surfaceflinger/LayerDim.cpp
rename to services/surfaceflinger/ColorLayer.cpp
index daebf8a..6923782 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -16,7 +16,7 @@
 
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
-#define LOG_TAG "LayerDim"
+#define LOG_TAG "ColorLayer"
 
 #include <stdlib.h>
 #include <stdint.h>
@@ -27,7 +27,7 @@
 
 #include <ui/GraphicBuffer.h>
 
-#include "LayerDim.h"
+#include "ColorLayer.h"
 #include "SurfaceFlinger.h"
 #include "DisplayDevice.h"
 #include "RenderEngine/RenderEngine.h"
@@ -35,31 +35,29 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-LayerDim::LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
+ColorLayer::ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags)
     : Layer(flinger, client, name, w, h, flags) {
 }
 
-LayerDim::~LayerDim() {
-}
-
-void LayerDim::onDraw(const sp<const DisplayDevice>& hw,
+void ColorLayer::onDraw(const sp<const DisplayDevice>& hw,
         const Region& /* clip */, bool useIdentityTransform) const
 {
     const State& s(getDrawingState());
-    if (s.alpha>0) {
+    if (s.color.a>0) {
         Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
         computeGeometry(hw, mesh, useIdentityTransform);
         RenderEngine& engine(mFlinger->getRenderEngine());
-        engine.setupDimLayerBlending(s.alpha);
+        engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
+              true /* disableTexture */, s.color);
         engine.drawMesh(mesh);
         engine.disableBlending();
     }
 }
 
-bool LayerDim::isVisible() const {
+bool ColorLayer::isVisible() const {
     const Layer::State& s(getDrawingState());
-    return !isHiddenByPolicy() && s.alpha;
+    return !isHiddenByPolicy() && s.color.a;
 }
 
 
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/ColorLayer.h
similarity index 81%
rename from services/surfaceflinger/LayerDim.h
rename to services/surfaceflinger/ColorLayer.h
index a0cfca9..ac3e2a9 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_LAYER_DIM_H
-#define ANDROID_LAYER_DIM_H
+#ifndef ANDROID_COLOR_LAYER_H
+#define ANDROID_COLOR_LAYER_H
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -26,14 +26,14 @@
 
 namespace android {
 
-class LayerDim : public Layer
+class ColorLayer : public Layer
 {
 public:
-                LayerDim(SurfaceFlinger* flinger, const sp<Client>& client,
+    ColorLayer(SurfaceFlinger* flinger, const sp<Client>& client,
                         const String8& name, uint32_t w, uint32_t h, uint32_t flags);
-        virtual ~LayerDim();
+    virtual ~ColorLayer() = default;
 
-    virtual const char* getTypeId() const { return "LayerDim"; }
+    virtual const char* getTypeId() const { return "ColorLayer"; }
     virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
             bool useIdentityTransform) const;
     virtual bool isOpaque(const Layer::State&) const { return false; }
@@ -46,4 +46,4 @@
 
 }; // namespace android
 
-#endif // ANDROID_LAYER_DIM_H
+#endif // ANDROID_COLOR_LAYER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index fd30e16..8734ee1 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -137,11 +137,7 @@
     mCurrentState.requestedFinalCrop = mCurrentState.finalCrop;
     mCurrentState.requestedCrop = mCurrentState.crop;
     mCurrentState.z = 0;
-#ifdef USE_HWC2
-    mCurrentState.alpha = 1.0f;
-#else
-    mCurrentState.alpha = 0xFF;
-#endif
+    mCurrentState.color.a = 1.0f;
     mCurrentState.layerStack = 0;
     mCurrentState.flags = layerFlags;
     mCurrentState.sequence = 0;
@@ -334,6 +330,10 @@
     return mName;
 }
 
+bool Layer::getPremultipledAlpha() const {
+    return mPremultipliedAlpha;
+}
+
 status_t Layer::setBuffers( uint32_t w, uint32_t h,
                             PixelFormat format, uint32_t flags)
 {
@@ -683,7 +683,7 @@
              " %s (%d)", mName.string(), to_string(blendMode).c_str(),
              to_string(error).c_str(), static_cast<int32_t>(error));
 #else
-    if (!isOpaque(s) || getAlpha() != 0xFF) {
+    if (!isOpaque(s) || getAlpha() != 1.0f) {
         layer.setBlending(mPremultipliedAlpha ?
                 HWC_BLENDING_PREMULT :
                 HWC_BLENDING_COVERAGE);
@@ -757,7 +757,7 @@
         hwcInfo.sourceCrop = sourceCrop;
     }
 
-    float alpha = getAlpha();
+    float alpha = static_cast<float>(getAlpha());
     error = hwcLayer->setPlaneAlpha(alpha);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set plane alpha %.3f: "
             "%s (%d)", mName.string(), alpha, to_string(error).c_str(),
@@ -787,7 +787,7 @@
     const Transform& tr(hw->getTransform());
     layer.setFrame(tr.transform(frame));
     layer.setCrop(computeCrop(hw));
-    layer.setPlaneAlpha(getAlpha());
+    layer.setPlaneAlpha(static_cast<uint8_t>(std::round(255.0f*getAlpha())));
 #endif
 
     /*
@@ -904,8 +904,11 @@
     if (mActiveBuffer == nullptr) {
         setCompositionType(hwcId, HWC2::Composition::SolidColor);
 
-        // For now, we only support black for DimLayer
-        error = hwcLayer->setColor({0, 0, 0, 255});
+        half4 color = getColor();
+        error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f*color.r)),
+                    static_cast<uint8_t>(std::round(255.0f * color.g)),
+                    static_cast<uint8_t>(std::round(255.0f * color.b)),
+                    255});
         if (error != HWC2::Error::None) {
             ALOGE("[%s] Failed to set color: %s (%d)", mName.string(),
                     to_string(error).c_str(), static_cast<int32_t>(error));
@@ -1254,7 +1257,8 @@
     texCoords[3] = vec2(right, 1.0f - top);
 
     RenderEngine& engine(mFlinger->getRenderEngine());
-    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), getAlpha());
+    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s),
+        false /* disableTexture */, getColor());
 #ifdef USE_HWC2
     engine.setSourceDataSpace(mCurrentState.dataSpace);
 #endif
@@ -1877,19 +1881,30 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
-#ifdef USE_HWC2
 bool Layer::setAlpha(float alpha) {
-#else
-bool Layer::setAlpha(uint8_t alpha) {
-#endif
-    if (mCurrentState.alpha == alpha)
+    if (mCurrentState.color.a == alpha)
         return false;
     mCurrentState.sequence++;
-    mCurrentState.alpha = alpha;
+    mCurrentState.color.a = alpha;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
+
+bool Layer::setColor(const half3& color) {
+    if (color.r == mCurrentState.color.r && color.g == mCurrentState.color.g
+        && color.b == mCurrentState.color.b)
+        return false;
+
+    mCurrentState.sequence++;
+    mCurrentState.color.r = color.r;
+    mCurrentState.color.g = color.g;
+    mCurrentState.color.b = color.b;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
     mCurrentState.sequence++;
     mCurrentState.requested.transform.set(
@@ -2141,13 +2156,8 @@
 }
 
 bool Layer::isVisible() const {
-#ifdef USE_HWC2
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f
             && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#else
-    return !(isHiddenByPolicy()) && getAlpha()
-            && (mActiveBuffer != NULL || mSidebandStream != NULL);
-#endif
 }
 
 bool Layer::allTransactionsSignaled() {
@@ -2439,7 +2449,7 @@
     info.mHeight = ds.active.h;
     info.mCrop = ds.crop;
     info.mFinalCrop = ds.finalCrop;
-    info.mAlpha = ds.alpha;
+    info.mColor = ds.color;
     info.mFlags = ds.flags;
     info.mPixelFormat = getPixelFormat();
     info.mDataSpace = getDataSpace();
@@ -2467,7 +2477,6 @@
     info.mContentDirty = contentDirty;
     return info;
 }
-
 #ifdef USE_HWC2
 void Layer::miniDumpHeader(String8& result) {
     result.append("----------------------------------------");
@@ -2791,23 +2800,17 @@
     return t * getDrawingState().active.transform;
 }
 
-#ifdef USE_HWC2
-float Layer::getAlpha() const {
+half Layer::getAlpha() const {
     const auto& p = mDrawingParent.promote();
 
-    float parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0;
-    return parentAlpha * getDrawingState().alpha;
+    half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
+    return parentAlpha * getDrawingState().color.a;
 }
-#else
-uint8_t Layer::getAlpha() const {
-    const auto& p = mDrawingParent.promote();
 
-    float parentAlpha = (p != nullptr) ? (p->getAlpha() / 255.0f) : 1.0;
-    float drawingAlpha = getDrawingState().alpha / 255.0f;
-    drawingAlpha = drawingAlpha * parentAlpha;
-    return static_cast<uint8_t>(std::round(drawingAlpha * 255));
+half4 Layer::getColor() const {
+    const half4 color(getDrawingState().color);
+    return half4(color.r, color.g, color.b, getAlpha());
 }
-#endif
 
 void Layer::commitChildList() {
     for (size_t i = 0; i < mCurrentChildren.size(); i++) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e7ece45..921492b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -51,6 +51,8 @@
 #include "RenderEngine/Mesh.h"
 #include "RenderEngine/Texture.h"
 
+#include <math/vec4.h>
+
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -119,11 +121,6 @@
         // to achieve mirroring.
         uint32_t layerStack;
 
-#ifdef USE_HWC2
-        float alpha;
-#else
-        uint8_t alpha;
-#endif
         uint8_t flags;
         uint8_t mask;
         uint8_t reserved[2];
@@ -158,6 +155,8 @@
 
         // A list of surfaces whose Z-order is interpreted relative to ours.
         SortedVector<wp<Layer>> zOrderRelatives;
+
+        half4 color;
     };
 
     // -----------------------------------------------------------------------
@@ -225,11 +224,8 @@
     bool setLayer(int32_t z);
     bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
 
-#ifdef USE_HWC2
     bool setAlpha(float alpha);
-#else
-    bool setAlpha(uint8_t alpha);
-#endif
+    bool setColor(const half3& color);
     bool setTransparentRegionHint(const Region& transparent);
     bool setFlags(uint8_t flags, uint8_t mask);
     bool setLayerStack(uint32_t layerStack);
@@ -509,11 +505,8 @@
     // Returns the Alpha of the Surface, accounting for the Alpha
     // of parent Surfaces in the hierarchy (alpha's will be multiplied
     // down the hierarchy).
-#ifdef USE_HWC2
-    float getAlpha() const;
-#else
-    uint8_t getAlpha() const;
-#endif
+    half getAlpha() const;
+    half4 getColor() const;
 
     void traverseInReverseZOrder(LayerVector::StateSet stateSet,
                                  const LayerVector::Visitor& visitor);
@@ -683,9 +676,8 @@
     sp<IGraphicBufferProducer> getProducer() const;
     const String8& getName() const;
     void notifyAvailableFrames();
-
     PixelFormat getPixelFormat() const { return mFormat; }
-
+    bool getPremultipledAlpha() const;
 private:
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index effd319..706960c 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -27,22 +27,15 @@
 namespace android {
 
 Description::Description() {
-    mPlaneAlpha = 1.0f;
     mPremultipliedAlpha = false;
     mOpaque = true;
     mTextureEnabled = false;
     mColorMatrixEnabled = false;
-
-    memset(mColor, 0, sizeof(mColor));
 }
 
 Description::~Description() {
 }
 
-void Description::setPlaneAlpha(GLclampf planeAlpha) {
-    mPlaneAlpha = planeAlpha;
-}
-
 void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
     mPremultipliedAlpha = premultipliedAlpha;
 }
@@ -60,11 +53,8 @@
     mTextureEnabled = false;
 }
 
-void Description::setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
-    mColor[0] = red;
-    mColor[1] = green;
-    mColor[2] = blue;
-    mColor[3] = alpha;
+void Description::setColor(const half4& color) {
+    mColor = color;
 }
 
 void Description::setProjectionMatrix(const mat4& mtx) {
diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h
index 3beffdf..cbac855 100644
--- a/services/surfaceflinger/RenderEngine/Description.h
+++ b/services/surfaceflinger/RenderEngine/Description.h
@@ -35,8 +35,6 @@
     friend class Program;
     friend class ProgramCache;
 
-    // value of the plane-alpha, between 0 and 1
-    GLclampf mPlaneAlpha;
     // whether textures are premultiplied
     bool mPremultipliedAlpha;
     // whether this layer is marked as opaque
@@ -46,8 +44,8 @@
     Texture mTexture;
     bool mTextureEnabled;
 
-    // color used when texturing is disabled
-    GLclampf mColor[4];
+    // color used when texturing is disabled or when setting alpha.
+    half4 mColor;
     // projection matrix
     mat4 mProjectionMatrix;
 
@@ -60,12 +58,11 @@
     Description();
     ~Description();
 
-    void setPlaneAlpha(GLclampf planeAlpha);
     void setPremultipliedAlpha(bool premultipliedAlpha);
     void setOpaque(bool opaque);
     void setTexture(const Texture& texture);
     void disableTexture();
-    void setColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    void setColor(const half4& color);
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
     const mat4& getColorMatrix() const;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 37a530b..daaa11e 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -204,25 +204,17 @@
     mVpHeight = vph;
 }
 
-#ifdef USE_HWC2
 void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha,
-        bool opaque, float alpha) {
-#else
-void GLES20RenderEngine::setupLayerBlending(
-    bool premultipliedAlpha, bool opaque, int alpha) {
-#endif
-
+        bool opaque, bool disableTexture, const half4& color) {
     mState.setPremultipliedAlpha(premultipliedAlpha);
     mState.setOpaque(opaque);
-#ifdef USE_HWC2
-    mState.setPlaneAlpha(alpha);
+    mState.setColor(color);
 
-    if (alpha < 1.0f || !opaque) {
-#else
-    mState.setPlaneAlpha(alpha / 255.0f);
+    if (disableTexture) {
+        mState.disableTexture();
+    }
 
-    if (alpha < 0xFF || !opaque) {
-#endif
+    if (color.a < 1.0f || !opaque) {
         glEnable(GL_BLEND);
         glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     } else {
@@ -231,33 +223,6 @@
 }
 
 #ifdef USE_HWC2
-void GLES20RenderEngine::setupDimLayerBlending(float alpha) {
-#else
-void GLES20RenderEngine::setupDimLayerBlending(int alpha) {
-#endif
-    mState.setPlaneAlpha(1.0f);
-    mState.setPremultipliedAlpha(true);
-    mState.setOpaque(false);
-#ifdef USE_HWC2
-    mState.setColor(0, 0, 0, alpha);
-#else
-    mState.setColor(0, 0, 0, alpha/255.0f);
-#endif
-    mState.disableTexture();
-
-#ifdef USE_HWC2
-    if (alpha == 1.0f) {
-#else
-    if (alpha == 0xFF) {
-#endif
-        glDisable(GL_BLEND);
-    } else {
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-    }
-}
-
-#ifdef USE_HWC2
 void GLES20RenderEngine::setColorMode(android_color_mode mode) {
     ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
 
@@ -355,10 +320,9 @@
 }
 
 void GLES20RenderEngine::setupFillWithColor(float r, float g, float b, float a) {
-    mState.setPlaneAlpha(1.0f);
     mState.setPremultipliedAlpha(true);
     mState.setOpaque(false);
-    mState.setColor(r, g, b, a);
+    mState.setColor(half4(r, g, b, a));
     mState.disableTexture();
     glDisable(GL_BLEND);
 }
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index eaf94af..5ac12fc 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -68,10 +68,9 @@
     virtual void setViewportAndProjection(size_t vpw, size_t vph,
             Rect sourceCrop, size_t hwh, bool yswap,
             Transform::orientation_flags rotation);
-#ifdef USE_HWC2
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            float alpha) override;
-    virtual void setupDimLayerBlending(float alpha) override;
+            bool disableTexture, const half4& color) override;
+#ifdef USE_HWC2
 
     // Color management related functions and state
     void setColorMode(android_color_mode mode);
@@ -92,10 +91,6 @@
 
     // Currently only supporting sRGB and DisplayP3 color spaces
     mat4 mSrgbToDisplayP3;
-#else
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            int alpha);
-    virtual void setupDimLayerBlending(int alpha);
 #endif
     bool mPlatformHasWideColor = false;
 
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 48a8da5..e95a6c5 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -22,6 +22,7 @@
 #include "Program.h"
 #include "ProgramCache.h"
 #include "Description.h"
+#include <math/mat4.h>
 
 namespace android {
 
@@ -63,7 +64,6 @@
         mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
         mSamplerLoc = glGetUniformLocation(programId, "sampler");
         mColorLoc = glGetUniformLocation(programId, "color");
-        mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane");
 
         // set-up the default values for our uniforms
         glUseProgram(programId);
@@ -132,11 +132,9 @@
         glUniform1i(mSamplerLoc, 0);
         glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray());
     }
-    if (mAlphaPlaneLoc >= 0) {
-        glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha);
-    }
     if (mColorLoc >= 0) {
-        glUniform4fv(mColorLoc, 1, desc.mColor);
+        const float* color = &static_cast<details::TVec4<float> const &>(desc.mColor)[0];
+        glUniform4fv(mColorLoc, 1, color);
     }
     if (mColorMatrixLoc >= 0) {
         glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray());
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index 36bd120..a2ae2ee 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -79,9 +79,6 @@
     /* location of the sampler uniform */
     GLint mSamplerLoc;
 
-    /* location of the alpha plane uniform */
-    GLint mAlphaPlaneLoc;
-
     /* location of the color uniform */
     GLint mColorLoc;
 };
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 06b2252..b437545 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -89,7 +89,7 @@
 void ProgramCache::primeCache() {
     uint32_t shaderCount = 0;
     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
-                       Key::PLANE_ALPHA_MASK | Key::TEXTURE_MASK;
+                       Key::ALPHA_MASK | Key::TEXTURE_MASK;
     // Prime the cache for all combinations of the above masks,
     // leaving off the experimental color matrix mask options.
 
@@ -122,8 +122,8 @@
             description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
             description.mTexture.getTextureTarget() == GL_TEXTURE_2D           ? Key::TEXTURE_2D :
             Key::TEXTURE_OFF)
-    .set(Key::PLANE_ALPHA_MASK,
-            (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
+    .set(Key::ALPHA_MASK,
+            (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
     .set(Key::BLEND_MASK,
             description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
     .set(Key::OPACITY_MASK,
@@ -168,12 +168,12 @@
     } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
         fs << "uniform sampler2D sampler;"
            << "varying vec2 outTexCoords;";
-    } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
+    }
+
+    if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) {
         fs << "uniform vec4 color;";
     }
-    if (needs.hasPlaneAlpha()) {
-        fs << "uniform float alphaPlane;";
-    }
+
     if (needs.hasColorMatrix()) {
         fs << "uniform mat4 colorMatrix;";
     }
@@ -225,18 +225,19 @@
     if (needs.isTexturing()) {
         fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
     } else {
-        fs << "gl_FragColor = color;";
+        fs << "gl_FragColor.rgb = color.rgb;";
+        fs << "gl_FragColor.a = 1.0;";
     }
     if (needs.isOpaque()) {
         fs << "gl_FragColor.a = 1.0;";
     }
-    if (needs.hasPlaneAlpha()) {
-        // modulate the alpha value with planeAlpha
+    if (needs.hasAlpha()) {
+        // modulate the current alpha value with alpha set
         if (needs.isPremultiplied()) {
             // ... and the color too if we're premultiplied
-            fs << "gl_FragColor *= alphaPlane;";
+            fs << "gl_FragColor *= color.a;";
         } else {
-            fs << "gl_FragColor.a *= alphaPlane;";
+            fs << "gl_FragColor.a *= color.a;";
         }
     }
 
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 5b0fbcd..ff5cf0f 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -57,9 +57,9 @@
             OPACITY_TRANSLUCENT     =       0x00000000,
             OPACITY_MASK            =       0x00000002,
 
-            PLANE_ALPHA_LT_ONE      =       0x00000004,
-            PLANE_ALPHA_EQ_ONE      =       0x00000000,
-            PLANE_ALPHA_MASK        =       0x00000004,
+            ALPHA_LT_ONE            =       0x00000004,
+            ALPHA_EQ_ONE            =       0x00000000,
+            ALPHA_MASK              =       0x00000004,
 
             TEXTURE_OFF             =       0x00000000,
             TEXTURE_EXT             =       0x00000008,
@@ -95,8 +95,8 @@
         inline bool isOpaque() const {
             return (mKey & OPACITY_MASK) == OPACITY_OPAQUE;
         }
-        inline bool hasPlaneAlpha() const {
-            return (mKey & PLANE_ALPHA_MASK) == PLANE_ALPHA_LT_ONE;
+        inline bool hasAlpha() const {
+            return (mKey & ALPHA_MASK) == ALPHA_LT_ONE;
         }
         inline bool hasColorMatrix() const {
             return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 9544579..fa65979 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -25,6 +25,7 @@
 #include <EGL/eglext.h>
 #include <math/mat4.h>
 #include <Transform.h>
+#include <gui/SurfaceControl.h>
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
@@ -98,16 +99,13 @@
     virtual void checkErrors() const;
     virtual void setViewportAndProjection(size_t vpw, size_t vph,
             Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0;
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
+            bool disableTexture, const half4& color) = 0;
 #ifdef USE_HWC2
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, float alpha) = 0;
-    virtual void setupDimLayerBlending(float alpha) = 0;
     virtual void setColorMode(android_color_mode mode) = 0;
     virtual void setSourceDataSpace(android_dataspace source) = 0;
     virtual void setWideColor(bool hasWideColor) = 0;
     virtual bool usesWideColor() = 0;
-#else
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, int alpha) = 0;
-    virtual void setupDimLayerBlending(int alpha) = 0;
 #endif
     virtual void setupLayerTexturing(const Texture& texture) = 0;
     virtual void setupLayerBlackedOut() = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e21379c..a7e7008 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -73,7 +73,7 @@
 #include "EventThread.h"
 #include "Layer.h"
 #include "LayerVector.h"
-#include "LayerDim.h"
+#include "ColorLayer.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 
@@ -2725,7 +2725,7 @@
                     case HWC2::Composition::SolidColor: {
                         const Layer::State& state(layer->getDrawingState());
                         if (layer->getClearClientTarget(hwcId) && !firstLayer &&
-                                layer->isOpaque(state) && (state.alpha == 1.0f)
+                                layer->isOpaque(state) && (state.color.a == 1.0f)
                                 && hasClientComposition) {
                             // never clear the very first layer since we're
                             // guaranteed the FB is already cleared
@@ -3065,6 +3065,10 @@
             if (layer->setAlpha(s.alpha))
                 flags |= eTraversalNeeded;
         }
+        if (what & layer_state_t::eColorChanged) {
+            if (layer->setColor(s.color))
+                flags |= eTraversalNeeded;
+        }
         if (what & layer_state_t::eMatrixChanged) {
             if (layer->setMatrix(s.matrix))
                 flags |= eTraversalNeeded;
@@ -3168,8 +3172,8 @@
                     uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
-        case ISurfaceComposerClient::eFXSurfaceDim:
-            result = createDimLayer(client,
+        case ISurfaceComposerClient::eFXSurfaceColor:
+            result = createColorLayer(client,
                     uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
@@ -3251,11 +3255,11 @@
     return err;
 }
 
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
 {
-    *outLayer = new LayerDim(this, client, name, w, h, flags);
+    *outLayer = new ColorLayer(this, client, name, w, h, flags);
     *handle = (*outLayer)->getHandle();
     *gbp = (*outLayer)->getProducer();
     return NO_ERROR;
@@ -4594,7 +4598,7 @@
                     ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
                             layer->isVisible() ? '+' : '-',
                             i, layer->getName().string(), layer->getLayerStack(), state.z,
-                            layer->isVisible(), state.flags, state.alpha);
+                            layer->isVisible(), state.flags, static_cast<float>(state.color.a));
                     i++;
                 });
             }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1b77aaf..e87d35f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -84,7 +84,7 @@
 class DisplayEventConnection;
 class EventThread;
 class Layer;
-class LayerDim;
+class ColorLayer;
 class Surface;
 class RenderEngine;
 class EventControlThread;
@@ -410,7 +410,7 @@
             sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
             sp<Layer>* outLayer);
 
-    status_t createDimLayer(const sp<Client>& client, const String8& name,
+    status_t createColorLayer(const sp<Client>& client, const String8& name,
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
             sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
 
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index b1c8c0a..b002138 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -71,7 +71,7 @@
 #include "EventThread.h"
 #include "Layer.h"
 #include "LayerVector.h"
-#include "LayerDim.h"
+#include "ColorLayer.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 
@@ -2024,7 +2024,7 @@
 
                 // compute the opaque region
                 const int32_t layerOrientation = tr.getOrientation();
-                if (s.alpha==255 && !translucent &&
+                if (layer->getAlpha()==1.0f && !translucent &&
                         ((layerOrientation & Transform::ROT_INVALID) == false)) {
                     // the opaque region is the layer's footprint
                     opaqueRegion = visibleRegion;
@@ -2297,7 +2297,7 @@
                         const Layer::State& state(layer->getDrawingState());
                         if ((cur->getHints() & HWC_HINT_CLEAR_FB)
                                 && i
-                                && layer->isOpaque(state) && (state.alpha == 0xFF)
+                                && layer->isOpaque(state) && (state.color.a == 1.0f)
                                 && hasGlesComposition) {
                             // never clear the very first layer since we're
                             // guaranteed the FB is already cleared
@@ -2622,9 +2622,14 @@
             }
         }
         if (what & layer_state_t::eAlphaChanged) {
-            if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+            if (layer->setAlpha(s.alpha))
                 flags |= eTraversalNeeded;
         }
+        if (what & layer_state_t::eColorChanged) {
+            if (layer->setColor(s.color)) {
+                flags |= eTraversalNeeded;
+            }
+        }
         if (what & layer_state_t::eMatrixChanged) {
             if (layer->setMatrix(s.matrix))
                 flags |= eTraversalNeeded;
@@ -2728,8 +2733,8 @@
                     uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
-        case ISurfaceComposerClient::eFXSurfaceDim:
-            result = createDimLayer(client,
+        case ISurfaceComposerClient::eFXSurfaceColor:
+            result = createColorLayer(client,
                     uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
@@ -2804,11 +2809,11 @@
     return err;
 }
 
-status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
 {
-    *outLayer = new LayerDim(this, client, name, w, h, flags);
+    *outLayer = new ColorLayer(this, client, name, w, h, flags);
     *handle = (*outLayer)->getHandle();
     *gbp = (*outLayer)->getProducer();
     return NO_ERROR;
@@ -4089,10 +4094,10 @@
             if (layer->getLayerStack() == hw->getLayerStack() && state.z >= minLayerZ &&
                     state.z <= maxLayerZ) {
                 layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-                    ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%x",
+                    ALOGE("%c index=%zu, name=%s, layerStack=%d, z=%d, visible=%d, flags=%x, alpha=%.3f",
                             layer->isVisible() ? '+' : '-',
                             i, layer->getName().string(), layer->getLayerStack(), state.z,
-                            layer->isVisible(), state.flags, state.alpha);
+                            layer->isVisible(), state.flags, static_cast<float>(state.color.a));
                     i++;
                 });
             }
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index db489b2..eeb4929 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -98,7 +98,7 @@
     addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(),
             layer->mCurrentState.active.transform.ty());
     addDepthLocked(transaction, layerId, layer->mCurrentState.z);
-    addAlphaLocked(transaction, layerId, layer->mCurrentState.alpha);
+    addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
     addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion);
     addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
     addCropLocked(transaction, layerId, layer->mCurrentState.crop);
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6be708a..5c188dc 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*"
+            "filter": "LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:LayerColorTest.*"
         }
 }
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 2119492..8900a4d 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -28,6 +28,7 @@
 #include <ui/DisplayInfo.h>
 
 #include <math.h>
+#include <math/vec3.h>
 
 namespace android {
 
@@ -1276,4 +1277,97 @@
     }
 }
 
+class LayerColorTest : public LayerUpdateTest {
+ protected:
+    void SetUp() override {
+        LayerUpdateTest::SetUp();
+
+        mLayerColorControl = mComposerClient->createSurface(
+            String8("Layer color surface"),
+            128, 128, PIXEL_FORMAT_RGBA_8888,
+            ISurfaceComposerClient::eFXSurfaceColor);
+
+        ASSERT_TRUE(mLayerColorControl != NULL);
+        ASSERT_TRUE(mLayerColorControl->isValid());
+
+        SurfaceComposerClient::openGlobalTransaction();
+        ASSERT_EQ(NO_ERROR, mLayerColorControl->setLayer(INT32_MAX-1));
+        ASSERT_EQ(NO_ERROR, mLayerColorControl->setPosition(140, 140));
+        ASSERT_EQ(NO_ERROR, mLayerColorControl->hide());
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->hide());
+        SurfaceComposerClient::closeGlobalTransaction(true);
+    }
+
+    void TearDown() override {
+        LayerUpdateTest::TearDown();
+        mLayerColorControl = 0;
+    }
+
+    sp<SurfaceControl> mLayerColorControl;
+};
+
+TEST_F(LayerColorTest, ColorLayerNoAlpha) {
+    sp<ScreenCapture> sc;
+
+    {
+        SCOPED_TRACE("before setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(145, 145);
+    }
+
+
+    SurfaceComposerClient::openGlobalTransaction();
+    half3 color(43.0f/255.0f, 207.0f/255.0f, 131.0f/255.0f);
+    mLayerColorControl->setColor(color);
+    mLayerColorControl->show();
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // There should now be a color
+        SCOPED_TRACE("after setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(145, 145, 43, 207, 131);
+    }
+}
+
+TEST_F(LayerColorTest, ColorLayerWithAlpha) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(145, 145);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    half3 color(43.0f/255.0f, 207.0f/255.0f, 131.0f/255.0f);
+    mLayerColorControl->setColor(color);
+    mLayerColorControl->setAlpha(.75f);
+    mLayerColorControl->show();
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // There should now be a color with .75 alpha
+        SCOPED_TRACE("after setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(145, 145, 48, 171, 147);
+    }
+}
+
+TEST_F(LayerColorTest, ColorLayerWithNoColor) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(145, 145);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    mLayerColorControl->show();
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // There should now be set to 0,0,0 (black) as default.
+        SCOPED_TRACE("after setColor");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(145, 145, 0, 0, 0);
+    }
+}
+
 }