Merge "Correctly release the OpenGL Canvas on EGL error."
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 24a9f87..0e294f71 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -50,7 +50,7 @@
     private boolean mRequested = true;
 
     /**
-     * Indicates that the current process cannot use hardware rendering.
+     * Invoke this method to disable hardware rendering in the current process.
      * 
      * @hide
      */
@@ -207,7 +207,7 @@
         EGLSurface mEglSurface;
         
         GL mGl;
-        GLES20Canvas mCanvas;
+        HardwareCanvas mCanvas;
 
         final int mGlVersion;
         final boolean mTranslucent;
@@ -279,12 +279,15 @@
                     if (error != EGL11.EGL_CONTEXT_LOST) {
                         // we'll try again if it was context lost
                         setRequested(false);
+                    } else {
+                        Log.w(LOG_TAG, "Mountain View, we've had a problem here. " 
+                                + "Switching back to software rendering.");
                     }
                     Log.w(LOG_TAG, "EGL error: " + getEGLErrorString(error));
                 }
             }
         }
-        
+
         @Override
         boolean initialize(SurfaceHolder holder) {
             if (isRequested() && !isEnabled()) {
@@ -654,6 +657,14 @@
         }
 
         @Override
+        void destroy(boolean full) {
+            super.destroy(full);
+            if (full && mGlCanvas != null) {
+                mGlCanvas = null;
+            }
+        }
+
+        @Override
         DisplayList createDisplayList() {
             return new GLES20DisplayList();
         }
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index baed5fd7..2187f24 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -26,39 +26,53 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 Program::Program(const char* vertex, const char* fragment) {
+    mInitialized = false;
+
     vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
-    fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+    if (vertexShader) {
 
-    id = glCreateProgram();
-    glAttachShader(id, vertexShader);
-    glAttachShader(id, fragmentShader);
-    glLinkProgram(id);
+        fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+        if (fragmentShader) {
 
-    GLint status;
-    glGetProgramiv(id, GL_LINK_STATUS, &status);
-    if (status != GL_TRUE) {
-        GLint infoLen = 0;
-        glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
-        if (infoLen > 1) {
-            GLchar log[infoLen];
-            glGetProgramInfoLog(id, infoLen, 0, &log[0]);
-            LOGE("Error while linking shaders: %s", log);
+            id = glCreateProgram();
+            glAttachShader(id, vertexShader);
+            glAttachShader(id, fragmentShader);
+            glLinkProgram(id);
+
+            GLint status;
+            glGetProgramiv(id, GL_LINK_STATUS, &status);
+            if (status != GL_TRUE) {
+                LOGE("Error while linking shaders:");
+                GLint infoLen = 0;
+                glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infoLen);
+                if (infoLen > 1) {
+                    GLchar log[infoLen];
+                    glGetProgramInfoLog(id, infoLen, 0, &log[0]);
+                    LOGE("%s", log);
+                }
+                glDeleteShader(vertexShader);
+                glDeleteShader(fragmentShader);
+                glDeleteProgram(id);
+            } else {
+                mInitialized = true;
+            }
         }
-        glDeleteShader(vertexShader);
-        glDeleteShader(fragmentShader);
-        glDeleteProgram(id);
     }
 
     mUse = false;
 
-    position = addAttrib("position");
-    transform = addUniform("transform");
+    if (mInitialized) {
+        position = addAttrib("position");
+        transform = addUniform("transform");
+    }
 }
 
 Program::~Program() {
-    glDeleteShader(vertexShader);
-    glDeleteShader(fragmentShader);
-    glDeleteProgram(id);
+    if (mInitialized) {
+        glDeleteShader(vertexShader);
+        glDeleteShader(fragmentShader);
+        glDeleteProgram(id);
+    }
 }
 
 int Program::addAttrib(const char* name) {
@@ -103,6 +117,7 @@
         glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]);
         LOGE("Error while compiling shader: %s", log);
         glDeleteShader(shader);
+        return 0;
     }
 
     return shader;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 5981662..afc6f3d 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -70,6 +70,13 @@
     }
 
     /**
+     * Indicates whether this program was correctly compiled and linked.
+     */
+    inline bool isInitialized() const {
+        return mInitialized;
+    }
+
+    /**
      * Binds the program with the specified projection, modelView and
      * transform matrices.
      */
@@ -126,6 +133,7 @@
     KeyedVector<const char*, int> uniforms;
 
     bool mUse;
+    bool mInitialized;
 }; // class Program
 
 }; // namespace uirenderer
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index f2f1adb..0b6c7b5 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -298,6 +298,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void ProgramCache::clear() {
+    PROGRAM_LOGD("Clearing program cache");
+
     size_t count = mCache.size();
     for (size_t i = 0; i < count; i++) {
         delete mCache.valueAt(i);