Show the unlocked padlock icon when there is an SSL authentication problem.

This introduces two changes in behaviour ...
- If the page's main resource uses SSL but there's a problem with it's
  certificate, show the open lock icon rather than the closed lock icon.
- If the page's main resource uses SSL and the certificate is good, but some
  sub-resources have problems with their certificates, show the open lock
  icon rather than the closed lock icon. Previously we would show the open
  lock icon only if these sub-resources did not use SSL.

Requires https://android-git.corp.google.com/g/#/c/139926.

Bug: 5403366
Change-Id: I0cb1b26d1180aacfbc500a944421e7b753cd95f1
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index e440d2c..a2a51d6 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -594,7 +594,10 @@
         Drawable d = null;
         if (securityState == SecurityState.SECURITY_STATE_SECURE) {
             d = mLockIconSecure;
-        } else if (securityState == SecurityState.SECURITY_STATE_MIXED) {
+        } else if (securityState == SecurityState.SECURITY_STATE_MIXED
+                || securityState == SecurityState.SECURITY_STATE_BAD_CERTIFICATE) {
+            // TODO: It would be good to have different icons for insecure vs mixed content.
+            // See http://b/5403800
             d = mLockIconMixed;
         }
         mNavigationBar.setLock(d);
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 936aca9..f2aa529 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -114,16 +114,19 @@
     }
 
     public enum SecurityState {
-        // The page does not use SSL.
+        // The page's main resource does not use SSL. Note that we use this
+        // state irrespective of the SSL authentication state of sub-resources.
         SECURITY_STATE_NOT_SECURE,
-        // The page uses SSL, the certificate is good and all elements are secure.
+        // The page's main resource uses SSL and the certificate is good. The
+        // same is true of all sub-resources.
         SECURITY_STATE_SECURE,
-        // The page uses SSL and the certificate is good, but some elements are insecure.
+        // The page's main resource uses SSL and the certificate is good, but
+        // some sub-resources either do not use SSL or have problems with their
+        // certificates.
         SECURITY_STATE_MIXED,
-        // TODO: Add SECURITY_STATE_BAD_CERTIFICATE
-        // See http://b/5403366
-        // The page uses SSL but there is a problem with the certificate.
-        //SECURITY_STATE_BAD_CERTIFICATE,
+        // The page's main resource uses SSL but there is a problem with its
+        // certificate.
+        SECURITY_STATE_BAD_CERTIFICATE,
     }
 
     Context mContext;
@@ -778,6 +781,7 @@
                             public void onClick(DialogInterface dialog,
                                     int whichButton) {
                                 handler.proceed();
+                                handleProceededAfterSslError(error);
                             }
                         })
                     .setNeutralButton(R.string.view_certificate,
@@ -813,6 +817,17 @@
         }
 
         /**
+         * Called when an SSL error occurred while loading a resource, but the
+         * WebView but chose to proceed anyway based on a decision retained
+         * from a previous response to onReceivedSslError(). We update our
+         * security state to reflect this.
+         */
+        @Override
+        public void onProceededAfterSslError(WebView view, SslError error) {
+            handleProceededAfterSslError(error);
+        }
+
+        /**
          * Displays client certificate request to the user.
          */
         @Override
@@ -2252,4 +2267,12 @@
         return builder.toString();
     }
 
+    private void handleProceededAfterSslError(SslError error) {
+        if (error.getUrl().equals(mCurrentState.mUrl)) {
+            // The security state should currently be SECURITY_STATE_SECURE.
+            setSecurityState(SecurityState.SECURITY_STATE_BAD_CERTIFICATE);
+        } else if (getSecurityState() == SecurityState.SECURITY_STATE_SECURE) {
+            setSecurityState(SecurityState.SECURITY_STATE_MIXED);
+        }
+    }
 }