commit 82e2435fd101e64854b8c56ac792c8a5522db4fe parent 0104c6562a3efe8702d5476188f61f159c180f77 Author: Dana Keeler <dkeeler@mozilla.com> Date: Fri, 21 Nov 2025 00:30:36 +0000 Bug 1795970 - engine-gecko: provide server certificate in onSecurityChange r=android-reviewers,boek Differential Revision: https://phabricator.services.mozilla.com/D272733 Diffstat:
9 files changed, 99 insertions(+), 41 deletions(-)
diff --git a/mobile/android/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt b/mobile/android/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngineSession.kt @@ -1080,11 +1080,11 @@ class GeckoEngineSession( } notifyObservers { - // TODO provide full certificate info: https://github.com/mozilla-mobile/android-components/issues/5557 onSecurityChange( securityInfo.isSecure, securityInfo.host, securityInfo.getIssuerName(), + securityInfo.certificate, ) } } diff --git a/mobile/android/android-components/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt b/mobile/android/android-components/components/browser/engine-gecko/src/test/java/mozilla/components/browser/engine/gecko/GeckoEngineSessionTest.kt @@ -246,7 +246,7 @@ class GeckoEngineSessionTest { object : EngineSession.Observer { override fun onLoadingStateChange(loading: Boolean) { observedLoadingState = loading } override fun onProgress(progress: Int) { observedProgress = progress } - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { // We cannot assert on actual parameters as SecurityInfo's fields can't be set // from the outside and its constructor isn't accessible either. observedSecurityChange = true @@ -864,7 +864,7 @@ class GeckoEngineSessionTest { var loadingStateChangeObserved = false engineSession.register( object : EngineSession.Observer { - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { observedSecurityChange = true } @@ -4384,10 +4384,12 @@ class GeckoEngineSessionTest { val engineSession = GeckoEngineSession(mock(), geckoSessionProvider = geckoSessionProvider) var observedIssuer: String? = null + var observedCertificate: X509Certificate? = null engineSession.register( object : EngineSession.Observer { - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { observedIssuer = issuer + observedCertificate = certificate } }, ) @@ -4404,6 +4406,7 @@ class GeckoEngineSessionTest { val securityInformation = MockSecurityInformation(certificate = certificate) progressDelegate.value.onSecurityChange(mock(), securityInformation) assertEquals(parsedIssuerName, observedIssuer) + assertEquals(certificate, observedCertificate) } @Test @@ -4411,10 +4414,12 @@ class GeckoEngineSessionTest { val engineSession = GeckoEngineSession(mock(), geckoSessionProvider = geckoSessionProvider) var observedIssuer: String? = null + var observedCertificate: X509Certificate? = null engineSession.register( object : EngineSession.Observer { - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { observedIssuer = issuer + observedCertificate = certificate } }, ) @@ -4431,6 +4436,7 @@ class GeckoEngineSessionTest { val securityInformation = MockSecurityInformation(certificate = certificate) progressDelegate.value.onSecurityChange(mock(), securityInformation) assertEquals(parsedIssuerName, observedIssuer) + assertEquals(certificate, observedCertificate) } @Test @@ -4438,10 +4444,12 @@ class GeckoEngineSessionTest { val engineSession = GeckoEngineSession(mock(), geckoSessionProvider = geckoSessionProvider) var observedIssuer: String? = null + var observedCertificate: X509Certificate? = null engineSession.register( object : EngineSession.Observer { - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { observedIssuer = issuer + observedCertificate = certificate } }, ) @@ -4458,6 +4466,7 @@ class GeckoEngineSessionTest { val securityInformation = MockSecurityInformation(certificate = certificate) progressDelegate.value.onSecurityChange(mock(), securityInformation) assertEquals(parsedIssuerName, observedIssuer) + assertEquals(certificate, observedCertificate) } @Test diff --git a/mobile/android/android-components/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineView.kt b/mobile/android/android-components/components/browser/engine-system/src/main/java/mozilla/components/browser/engine/system/SystemEngineView.kt @@ -187,6 +187,9 @@ class SystemEngineView @JvmOverloads constructor( secure = cert != null, host = cert?.let { url.toUri().host }, issuer = cert?.issuedBy?.oName, + // Bug 2000336: when the minimum API version is 29, + // this can use cert?.x509Certificate. + certificate = null, ) } } diff --git a/mobile/android/android-components/components/browser/engine-system/src/test/java/mozilla/components/browser/engine/system/SystemEngineViewTest.kt b/mobile/android/android-components/components/browser/engine-system/src/test/java/mozilla/components/browser/engine/system/SystemEngineViewTest.kt @@ -76,6 +76,7 @@ import org.mockito.Mockito.verifyNoInteractions import org.robolectric.Robolectric import org.robolectric.annotation.Config import java.io.StringReader +import java.security.cert.X509Certificate @RunWith(AndroidJUnit4::class) class SystemEngineViewTest { @@ -108,7 +109,10 @@ class SystemEngineViewTest { var observedUrl = "" var observedUserGesture = true var observedLoadingState = false - var observedSecurityChange: Triple<Boolean, String?, String?> = Triple(false, null, null) + var observedSecure = false + var observedHost: String? = null + var observedIssuer: String? = null + var observedCertificate: X509Certificate? = null engineSession.register( object : EngineSession.Observer { override fun onLoadingStateChange(loading: Boolean) { observedLoadingState = loading } @@ -116,8 +120,11 @@ class SystemEngineViewTest { observedUrl = url observedUserGesture = hasUserGesture } - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { - observedSecurityChange = Triple(secure, host, issuer) + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { + observedSecure = secure + observedHost = host + observedIssuer = issuer + observedCertificate = certificate } }, ) @@ -131,11 +138,17 @@ class SystemEngineViewTest { assertEquals("http://mozilla.org", observedUrl) assertEquals(false, observedUserGesture) assertFalse(observedLoadingState) - assertEquals(Triple(false, null, null), observedSecurityChange) + assertFalse(observedSecure) + assertNull(observedHost) + assertNull(observedIssuer) + assertNull(observedCertificate) val view = mock<WebView>() engineSession.webView.webViewClient.onPageFinished(view, "http://mozilla.org") - assertEquals(Triple(false, null, null), observedSecurityChange) + assertFalse(observedSecure) + assertNull(observedHost) + assertNull(observedIssuer) + assertNull(observedCertificate) val certificate = mock<SslCertificate>() val dName = mock<SslCertificate.DName>() @@ -147,7 +160,10 @@ class SystemEngineViewTest { doReturn(dName).`when`(certificate).issuedBy doReturn(certificate).`when`(view).certificate engineSession.webView.webViewClient.onPageFinished(view, "http://mozilla.org") - assertEquals(Triple(true, "mozilla.org", "testCA"), observedSecurityChange) + assertTrue(observedSecure) + assertEquals("mozilla.org", observedHost) + assertEquals("testCA", observedIssuer) + assertNull(observedCertificate) } @Test @@ -931,13 +947,19 @@ class SystemEngineViewTest { var observedUrl = "" var observedLoadingState = true - var observedSecurityChange: Triple<Boolean, String?, String?> = Triple(false, null, null) + var observedSecure = false + var observedHost: String? = null + var observedIssuer: String? = null + var observedCertificate: X509Certificate? = null engineSession.register( object : EngineSession.Observer { override fun onLoadingStateChange(loading: Boolean) { observedLoadingState = loading } override fun onLocationChange(url: String, hasUserGesture: Boolean) { observedUrl = url } - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { - observedSecurityChange = Triple(secure, host, issuer) + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { + observedSecure = secure + observedHost = host + observedIssuer = issuer + observedCertificate = certificate } }, ) @@ -954,7 +976,10 @@ class SystemEngineViewTest { engineSession.webView.webViewClient.onPageFinished(view, "invalid:") assertEquals("invalid:", observedUrl) assertFalse(observedLoadingState) - assertEquals(Triple(true, null, "testCA"), observedSecurityChange) + assertTrue(observedSecure) + assertNull(observedHost) + assertEquals("testCA", observedIssuer) + assertNull(observedCertificate) } @Test diff --git a/mobile/android/android-components/components/browser/state/src/main/java/mozilla/components/browser/state/engine/EngineObserver.kt b/mobile/android/android-components/components/browser/state/src/main/java/mozilla/components/browser/state/engine/EngineObserver.kt @@ -40,6 +40,7 @@ import mozilla.components.concept.engine.window.WindowRequest import mozilla.components.concept.fetch.Headers.Names.E_TAG import mozilla.components.concept.fetch.Response import mozilla.components.lib.state.Store +import java.security.cert.X509Certificate private const val PAGE_LOAD_COMPLETION_PROGRESS = 100 @@ -158,11 +159,11 @@ internal class EngineObserver( } } - override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?) { + override fun onSecurityChange(secure: Boolean, host: String?, issuer: String?, certificate: X509Certificate?) { store.dispatch( ContentAction.UpdateSecurityInfoAction( tabId, - SecurityInfoState(secure, host ?: "", issuer ?: ""), + SecurityInfoState(secure, host ?: "", issuer ?: "", certificate), ), ) } diff --git a/mobile/android/android-components/components/browser/state/src/main/java/mozilla/components/browser/state/state/SecurityInfoState.kt b/mobile/android/android-components/components/browser/state/src/main/java/mozilla/components/browser/state/state/SecurityInfoState.kt @@ -4,16 +4,20 @@ package mozilla.components.browser.state.state +import java.security.cert.X509Certificate + /** * A value type holding security information for a Session. * * @property secure true if the tab is currently pointed to a URL with * a valid SSL certificate, otherwise false. - * @property host domain for which the SSL certificate was issued. + * @property host domain for which the certificate was issued. * @property issuer name of the certificate authority who issued the SSL certificate. + * @property certificate the certificate in question. */ data class SecurityInfoState( val secure: Boolean = false, val host: String = "", val issuer: String = "", + val certificate: X509Certificate? = null, ) diff --git a/mobile/android/android-components/components/browser/state/src/test/java/mozilla/components/browser/state/engine/EngineObserverTest.kt b/mobile/android/android-components/components/browser/state/src/test/java/mozilla/components/browser/state/engine/EngineObserverTest.kt @@ -217,7 +217,7 @@ class EngineObserverTest { textDirectiveUserActivation: Boolean, ) { if (url.startsWith("https://")) { - notifyObservers { onSecurityChange(true, "host", "issuer") } + notifyObservers { onSecurityChange(true, "host", "issuer", null) } } else { notifyObservers { onSecurityChange(false) } } diff --git a/mobile/android/android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt b/mobile/android/android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/EngineSession.kt @@ -25,6 +25,7 @@ import mozilla.components.concept.fetch.Response import mozilla.components.support.base.observer.Observable import mozilla.components.support.base.observer.ObserverRegistry import org.json.JSONObject +import java.security.cert.X509Certificate /** * Class representing a single engine session. @@ -60,7 +61,22 @@ abstract class EngineSession( fun onProgress(progress: Int) = Unit fun onLoadingStateChange(loading: Boolean) = Unit fun onNavigationStateChange(canGoBack: Boolean? = null, canGoForward: Boolean? = null) = Unit - fun onSecurityChange(secure: Boolean, host: String? = null, issuer: String? = null) = Unit + + /** + * Event to indicate the top-level connection security has changed. + * + * @param secure If true, the connection is considered secure (e.g. delivered over TLS with no errors). + * @param host The domain name of the server that was connected to. + * @param issuer The name of the organization that issued the server certificate, if present. + * @param certificate The certificate presented by the server, if any. + */ + fun onSecurityChange( + secure: Boolean, + host: String? = null, + issuer: String? = null, + certificate: X509Certificate? = null, + ) = Unit + fun onTrackerBlockingEnabledChange(enabled: Boolean) = Unit /** diff --git a/mobile/android/android-components/components/concept/engine/src/test/java/mozilla/components/concept/engine/EngineSessionTest.kt b/mobile/android/android-components/components/concept/engine/src/test/java/mozilla/components/concept/engine/EngineSessionTest.kt @@ -55,7 +55,7 @@ class EngineSessionTest { session.notifyInternalObservers { onProgress(25) } session.notifyInternalObservers { onProgress(100) } session.notifyInternalObservers { onLoadingStateChange(true) } - session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } + session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer", null) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onExcludedOnTrackingProtectionChange(true) } @@ -90,7 +90,7 @@ class EngineSessionTest { verify(observer).onProgress(25) verify(observer).onProgress(100) verify(observer).onLoadingStateChange(true) - verify(observer).onSecurityChange(true, "mozilla.org", "issuer") + verify(observer).onSecurityChange(true, "mozilla.org", "issuer", null) verify(observer).onTrackerBlockingEnabledChange(true) verify(observer).onTrackerBlocked(tracker) verify(observer).onExcludedOnTrackingProtectionChange(true) @@ -137,7 +137,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLocationChange("https://www.mozilla.org", false) } session.notifyInternalObservers { onProgress(25) } session.notifyInternalObservers { onLoadingStateChange(true) } - session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } + session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer", null) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } @@ -166,7 +166,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLocationChange("https://www.firefox.com", false) } session.notifyInternalObservers { onProgress(100) } session.notifyInternalObservers { onLoadingStateChange(false) } - session.notifyInternalObservers { onSecurityChange(false, "", "") } + session.notifyInternalObservers { onSecurityChange(false, "", "", null) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(false) } session.notifyInternalObservers { onLongPress(otherHitResult) } @@ -196,7 +196,7 @@ class EngineSessionTest { verify(observer).onLocationChange("https://www.mozilla.org", false) verify(observer).onProgress(25) verify(observer).onLoadingStateChange(true) - verify(observer).onSecurityChange(true, "mozilla.org", "issuer") + verify(observer).onSecurityChange(true, "mozilla.org", "issuer", null) verify(observer).onTrackerBlockingEnabledChange(true) verify(observer).onTrackerBlocked(tracker) verify(observer).onLongPress(unknownHitResult) @@ -217,7 +217,7 @@ class EngineSessionTest { verify(observer, never()).onLocationChange("https://www.firefox.com", false) verify(observer, never()).onProgress(100) verify(observer, never()).onLoadingStateChange(false) - verify(observer, never()).onSecurityChange(false, "", "") + verify(observer, never()).onSecurityChange(false, "", "", null) verify(observer, never()).onTrackerBlockingEnabledChange(false) verify(observer, never()).onTrackerBlocked(Tracker("Tracker")) verify(observer, never()).onLongPress(otherHitResult) @@ -262,7 +262,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLocationChange("https://www.mozilla.org", false) } session.notifyInternalObservers { onProgress(25) } session.notifyInternalObservers { onLoadingStateChange(true) } - session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } + session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer", null) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } @@ -289,7 +289,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLocationChange("https://www.firefox.com", false) } session.notifyInternalObservers { onProgress(100) } session.notifyInternalObservers { onLoadingStateChange(false) } - session.notifyInternalObservers { onSecurityChange(false, "", "") } + session.notifyInternalObservers { onSecurityChange(false, "", "", null) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(false) } session.notifyInternalObservers { onLongPress(otherHitResult) } @@ -316,7 +316,7 @@ class EngineSessionTest { verify(observer).onLocationChange("https://www.mozilla.org", false) verify(observer).onProgress(25) verify(observer).onLoadingStateChange(true) - verify(observer).onSecurityChange(true, "mozilla.org", "issuer") + verify(observer).onSecurityChange(true, "mozilla.org", "issuer", null) verify(observer).onTrackerBlockingEnabledChange(true) verify(observer).onTrackerBlocked(tracker) verify(observer).onLongPress(unknownHitResult) @@ -334,7 +334,7 @@ class EngineSessionTest { verify(observer, never()).onLocationChange("https://www.firefox.com", false) verify(observer, never()).onProgress(100) verify(observer, never()).onLoadingStateChange(false) - verify(observer, never()).onSecurityChange(false, "", "") + verify(observer, never()).onSecurityChange(false, "", "", null) verify(observer, never()).onTrackerBlockingEnabledChange(false) verify(observer, never()).onTrackerBlocked(Tracker("Tracker")) verify(observer, never()).onLongPress(otherHitResult) @@ -359,7 +359,7 @@ class EngineSessionTest { verify(otherObserver, never()).onLocationChange("https://www.firefox.com", false) verify(otherObserver, never()).onProgress(100) verify(otherObserver, never()).onLoadingStateChange(false) - verify(otherObserver, never()).onSecurityChange(false, "", "") + verify(otherObserver, never()).onSecurityChange(false, "", "", null) verify(otherObserver, never()).onTrackerBlockingEnabledChange(false) verify(otherObserver, never()).onTrackerBlocked(Tracker("Tracker")) verify(otherObserver, never()).onLongPress(otherHitResult) @@ -399,7 +399,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLocationChange("https://www.mozilla.org", false) } session.notifyInternalObservers { onProgress(25) } session.notifyInternalObservers { onLoadingStateChange(true) } - session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } + session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer", null) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } @@ -426,7 +426,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLocationChange("https://www.firefox.com", false) } session.notifyInternalObservers { onProgress(100) } session.notifyInternalObservers { onLoadingStateChange(false) } - session.notifyInternalObservers { onSecurityChange(false, "", "") } + session.notifyInternalObservers { onSecurityChange(false, "", "", null) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(false) } session.notifyInternalObservers { onLongPress(otherHitResult) } @@ -453,7 +453,7 @@ class EngineSessionTest { verify(observer).onLocationChange("https://www.mozilla.org", false) verify(observer).onProgress(25) verify(observer).onLoadingStateChange(true) - verify(observer).onSecurityChange(true, "mozilla.org", "issuer") + verify(observer).onSecurityChange(true, "mozilla.org", "issuer", null) verify(observer).onTrackerBlockingEnabledChange(true) verify(observer).onTrackerBlocked(tracker) verify(observer).onLongPress(unknownHitResult) @@ -471,7 +471,7 @@ class EngineSessionTest { verify(observer, never()).onLocationChange("https://www.firefox.com", false) verify(observer, never()).onProgress(100) verify(observer, never()).onLoadingStateChange(false) - verify(observer, never()).onSecurityChange(false, "", "") + verify(observer, never()).onSecurityChange(false, "", "", null) verify(observer, never()).onTrackerBlockingEnabledChange(false) verify(observer, never()).onTrackerBlocked(Tracker("Tracker")) verify(observer, never()).onLongPress(otherHitResult) @@ -515,7 +515,7 @@ class EngineSessionTest { otherSession.notifyInternalObservers { onLocationChange("https://www.mozilla.org", false) } otherSession.notifyInternalObservers { onProgress(25) } otherSession.notifyInternalObservers { onLoadingStateChange(true) } - otherSession.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } + otherSession.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer", null) } otherSession.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } otherSession.notifyInternalObservers { onTrackerBlocked(tracker) } otherSession.notifyInternalObservers { onLongPress(unknownHitResult) } @@ -541,7 +541,7 @@ class EngineSessionTest { verify(observer, never()).onLocationChange("https://www.mozilla.org", false) verify(observer, never()).onProgress(25) verify(observer, never()).onLoadingStateChange(true) - verify(observer, never()).onSecurityChange(true, "mozilla.org", "issuer") + verify(observer, never()).onSecurityChange(true, "mozilla.org", "issuer", null) verify(observer, never()).onTrackerBlockingEnabledChange(true) verify(observer, never()).onTrackerBlocked(tracker) verify(observer, never()).onLongPress(unknownHitResult) @@ -568,7 +568,7 @@ class EngineSessionTest { session.notifyInternalObservers { onLocationChange("https://www.mozilla.org", false) } session.notifyInternalObservers { onProgress(25) } session.notifyInternalObservers { onLoadingStateChange(true) } - session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer") } + session.notifyInternalObservers { onSecurityChange(true, "mozilla.org", "issuer", null) } session.notifyInternalObservers { onTrackerBlockingEnabledChange(true) } session.notifyInternalObservers { onTrackerBlocked(tracker) } session.notifyInternalObservers { onLongPress(unknownHitResult) } @@ -594,7 +594,7 @@ class EngineSessionTest { verify(observer, times(1)).onLocationChange("https://www.mozilla.org", false) verify(observer, times(1)).onProgress(25) verify(observer, times(1)).onLoadingStateChange(true) - verify(observer, times(1)).onSecurityChange(true, "mozilla.org", "issuer") + verify(observer, times(1)).onSecurityChange(true, "mozilla.org", "issuer", null) verify(observer, times(1)).onTrackerBlockingEnabledChange(true) verify(observer, times(1)).onTrackerBlocked(tracker) verify(observer, times(1)).onLongPress(unknownHitResult) @@ -948,7 +948,7 @@ class EngineSessionTest { observer.onProgress(25) observer.onProgress(100) observer.onLoadingStateChange(true) - observer.onSecurityChange(true, "mozilla.org", "issuer") + observer.onSecurityChange(true, "mozilla.org", "issuer", null) observer.onTrackerBlockingEnabledChange(true) observer.onTrackerBlocked(tracker) observer.onExcludedOnTrackingProtectionChange(true)