SurfaceFlinger: screenshots w/ protected buffers

This change modifies SurfaceFlinger's screenshot behavior when a layer
with a protected buffer is visible.  The previous behavior was to simply
fail the screenshot.  The new behavior is to render the screenshot using
a placeholder texture where the protected buffer would have been.

Change-Id: I5e50cb2f3b31b2ea81cfe291c9b4a42e9ee71874
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 41d7a90..feb2c52 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -280,20 +280,29 @@
         return;
     }
 
-    const GLenum target = GL_TEXTURE_EXTERNAL_OES;
-    glBindTexture(target, mTextureName);
-    if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
-        // TODO: we could be more subtle with isFixedSize()
-        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    GLenum target = GL_TEXTURE_EXTERNAL_OES;
+    if (!isProtected()) {
+        glBindTexture(target, mTextureName);
+        if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
+            // TODO: we could be more subtle with isFixedSize()
+            glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+            glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        } else {
+            glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+            glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        }
+        glEnable(target);
+        glMatrixMode(GL_TEXTURE);
+        glLoadMatrixf(mTextureMatrix);
+        glMatrixMode(GL_MODELVIEW);
     } else {
-        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        target = GL_TEXTURE_2D;
+        glBindTexture(target, mFlinger->getProtectedTexName());
+        glEnable(target);
+        glMatrixMode(GL_TEXTURE);
+        glLoadIdentity();
+        glMatrixMode(GL_MODELVIEW);
     }
-    glEnable(target);
-    glMatrixMode(GL_TEXTURE);
-    glLoadMatrixf(mTextureMatrix);
-    glMatrixMode(GL_MODELVIEW);
 
     drawWithOpenGL(clip);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3f154ce..b01a6a3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -275,7 +275,7 @@
 
     const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
     const uint16_t g1 = pack565(0x17,0x2f,0x17);
-    const uint16_t textureData[4] = { g0, g1, g1, g0 };
+    const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };
     glGenTextures(1, &mWormholeTexName);
     glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -283,7 +283,17 @@
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
-            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
+            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData);
+
+    const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) };
+    glGenTextures(1, &mProtectedTexName);
+    glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
+            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
 
     glViewport(0, 0, w, h);
     glMatrixMode(GL_PROJECTION);
@@ -2255,22 +2265,6 @@
     if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
         return BAD_VALUE;
 
-    // make sure none of the layers are protected
-    const LayerVector& layers(mDrawingState.layersSortedByZ);
-    const size_t count = layers.size();
-    for (size_t i=0 ; i<count ; ++i) {
-        const sp<LayerBase>& layer(layers[i]);
-        const uint32_t flags = layer->drawingState().flags;
-        if (!(flags & ISurfaceComposer::eLayerHidden)) {
-            const uint32_t z = layer->drawingState().z;
-            if (z >= minLayerZ && z <= maxLayerZ) {
-                if (layer->isProtected()) {
-                    return INVALID_OPERATION;
-                }
-            }
-        }
-    }
-
     if (!GLExtensions::getInstance().haveFramebufferObject())
         return INVALID_OPERATION;
 
@@ -2320,6 +2314,8 @@
         glClearColor(0,0,0,1);
         glClear(GL_COLOR_BUFFER_BIT);
 
+        const LayerVector& layers(mDrawingState.layersSortedByZ);
+        const size_t count = layers.size();
         for (size_t i=0 ; i<count ; ++i) {
             const sp<LayerBase>& layer(layers[i]);
             const uint32_t flags = layer->drawingState().flags;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 128a64d..92b265e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -192,6 +192,8 @@
 
     sp<Layer> getLayer(const sp<ISurface>& sur) const;
 
+    GLuint getProtectedTexName() const { return mProtectedTexName; }
+
 private:
     // DeathRecipient interface
     virtual void binderDied(const wp<IBinder>& who);
@@ -349,6 +351,7 @@
                 sp<IMemoryHeap>             mServerHeap;
                 surface_flinger_cblk_t*     mServerCblk;
                 GLuint                      mWormholeTexName;
+                GLuint                      mProtectedTexName;
                 nsecs_t                     mBootTime;
 
                 // Can only accessed from the main thread, these members