diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index a5c011b0700..9e3d8a6c3fd 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -367,6 +367,7 @@ + diff --git a/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs b/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs index 40fe7d85965..b31a8a804d1 100644 --- a/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs +++ b/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs @@ -157,7 +157,15 @@ public CookieContainer CookieContainer public bool CheckCertificateRevocationList { get; set; } = false; - public Func ServerCertificateCustomValidationCallback { get; set; } + X509TrustManagerWithValidationCallback.Helper? _callbackTrustManagerHelper = null; + + public Func? ServerCertificateCustomValidationCallback + { + get => _callbackTrustManagerHelper?.Callback; + set { + _callbackTrustManagerHelper = value != null ? new X509TrustManagerWithValidationCallback.Helper (value) : null; + } + } // See: https://developer.android.com/reference/javax/net/ssl/SSLSocket#protocols public SslProtocols SslProtocols { get; set; } = @@ -199,7 +207,7 @@ public int MaxAutomaticRedirections /// If the website requires authentication, this property will contain data about each scheme supported /// by the server after the response. Note that unauthorized request will return a valid response - you /// need to check the status code and and (re)configure AndroidMessageHandler instance accordingly by providing - /// both the credentials and the authentication scheme by setting the + /// both the credentials and the authentication scheme by setting the /// property. If AndroidMessageHandler is not able to detect the kind of authentication scheme it will store an /// instance of with its property /// set to AuthenticationScheme.Unsupported and the application will be responsible for providing an @@ -939,7 +947,7 @@ void AppendEncoding (string encoding, ref List ? list) // SSL context must be set up as soon as possible, before adding any content or // headers. Otherwise Java won't use the socket factory - SetupSSL (httpConnection as HttpsURLConnection); + SetupSSL (httpConnection as HttpsURLConnection, request); if (request.Content != null) AddHeaders (httpConnection, request.Content.Headers); AddHeaders (httpConnection, request.Headers); @@ -997,7 +1005,7 @@ void AppendEncoding (string encoding, ref List ? list) internal SSLSocketFactory? ConfigureCustomSSLSocketFactoryInternal (HttpsURLConnection connection) => ConfigureCustomSSLSocketFactoryInternal (connection); - void SetupSSL (HttpsURLConnection? httpsConnection) + void SetupSSL (HttpsURLConnection? httpsConnection, HttpRequestMessage requestMessage) { if (httpsConnection == null) return; @@ -1017,35 +1025,48 @@ void SetupSSL (HttpsURLConnection? httpsConnection) } #endif - var keyStore = KeyStore.GetInstance (KeyStore.DefaultType); - keyStore?.Load (null, null); - bool gotCerts = TrustedCerts?.Count > 0; - if (gotCerts) { - for (int i = 0; i < TrustedCerts!.Count; i++) { - Certificate cert = TrustedCerts [i]; - if (cert == null) - continue; - keyStore?.SetCertificateEntry ($"ca{i}", cert); - } - } + var keyStore = InitializeKeyStore (out bool gotCerts); keyStore = ConfigureKeyStore (keyStore); var kmf = ConfigureKeyManagerFactory (keyStore); var tmf = ConfigureTrustManagerFactory (keyStore); if (tmf == null) { - // If there are no certs and no trust manager factory, we can't use a custom manager - // because it will cause all the HTTPS requests to fail because of unverified trust - // chain - if (!gotCerts) + // If there are no trusted certs, no custom trust manager factory or custom certificate validation callback + // there is no point in changing the behavior of the default SSL socket factory + if (!gotCerts && _callbackTrustManagerHelper == null) return; tmf = TrustManagerFactory.GetInstance (TrustManagerFactory.DefaultAlgorithm); - tmf?.Init (keyStore); + tmf?.Init (gotCerts ? keyStore : null); // only use the custom key store if the user defined any trusted certs + } + + ITrustManager[]? trustManagers = tmf?.GetTrustManagers (); + + if (_callbackTrustManagerHelper != null) { + trustManagers = _callbackTrustManagerHelper.Inject (trustManagers, requestMessage); } var context = SSLContext.GetInstance ("TLS"); - context?.Init (kmf?.GetKeyManagers (), tmf?.GetTrustManagers (), null); + context?.Init (kmf?.GetKeyManagers (), trustManagers, null); httpsConnection.SSLSocketFactory = context?.SocketFactory; + + KeyStore? InitializeKeyStore (out bool gotCerts) + { + var keyStore = KeyStore.GetInstance (KeyStore.DefaultType); + keyStore?.Load (null, null); + gotCerts = TrustedCerts?.Count > 0; + + if (gotCerts) { + for (int i = 0; i < TrustedCerts!.Count; i++) { + Certificate cert = TrustedCerts [i]; + if (cert == null) + continue; + keyStore?.SetCertificateEntry ($"ca{i}", cert); + } + } + + return keyStore; + } } void HandlePreAuthentication (HttpURLConnection httpConnection) @@ -1116,4 +1137,4 @@ void SetupRequestBody (HttpURLConnection httpConnection, HttpRequestMessage requ } } -} \ No newline at end of file +} diff --git a/src/Mono.Android/Xamarin.Android.Net/X509TrustManagerWithValidationCallback.cs b/src/Mono.Android/Xamarin.Android.Net/X509TrustManagerWithValidationCallback.cs new file mode 100644 index 00000000000..7eafe3ebd2e --- /dev/null +++ b/src/Mono.Android/Xamarin.Android.Net/X509TrustManagerWithValidationCallback.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; + +using Javax.Net.Ssl; + +using JavaCertificateException = Java.Security.Cert.CertificateException; +using JavaX509Certificate = Java.Security.Cert.X509Certificate; + +namespace Xamarin.Android.Net +{ + internal sealed class X509TrustManagerWithValidationCallback : Java.Lang.Object, IX509TrustManager + { + internal sealed class Helper + { + public Func Callback { get; } + + public Helper (Func callback) + { + Callback = callback; + } + + public ITrustManager[] Inject ( + ITrustManager[]? trustManagers, + HttpRequestMessage requestMessage) + { + IX509TrustManager? x509TrustManager = trustManagers?.OfType ().FirstOrDefault (); + IEnumerable otherTrustManagers = trustManagers?.Where (manager => manager != x509TrustManager) ?? Enumerable.Empty (); + var trustManagerWithCallback = new X509TrustManagerWithValidationCallback (x509TrustManager, requestMessage, Callback); + return otherTrustManagers.Prepend (trustManagerWithCallback).ToArray (); + } + } + + private readonly IX509TrustManager? _internalTrustManager; + private readonly HttpRequestMessage _request; + private readonly Func _serverCertificateCustomValidationCallback; + + private X509TrustManagerWithValidationCallback ( + IX509TrustManager? internalTrustManager, + HttpRequestMessage request, + Func serverCertificateCustomValidationCallback) + { + _request = request; + _internalTrustManager = internalTrustManager; + _serverCertificateCustomValidationCallback = serverCertificateCustomValidationCallback; + } + + public void CheckServerTrusted (JavaX509Certificate[] javaChain, string authType) + { + var sslPolicyErrors = SslPolicyErrors.None; + var certificates = ConvertCertificates (javaChain); + + try { + _internalTrustManager?.CheckServerTrusted (javaChain, authType); + } catch (JavaCertificateException) { + sslPolicyErrors |= SslPolicyErrors.RemoteCertificateChainErrors; + } + + X509Certificate2? certificate = certificates.FirstOrDefault (); + using X509Chain chain = CreateChain (certificates); + + if (certificate == null) { + sslPolicyErrors |= SslPolicyErrors.RemoteCertificateNotAvailable; + } + + if (!_serverCertificateCustomValidationCallback (_request, certificate, chain, sslPolicyErrors)) { + throw new JavaCertificateException ("The remote certificate was rejected by the provided RemoteCertificateValidationCallback."); + } + } + + public void CheckClientTrusted (JavaX509Certificate[] chain, string authType) + => _internalTrustManager?.CheckClientTrusted (chain, authType); + + public JavaX509Certificate[] GetAcceptedIssuers () + => _internalTrustManager?.GetAcceptedIssuers () ?? Array.Empty (); + + private static X509Chain CreateChain (X509Certificate2[] certificates) + { + // the chain initialization is based on dotnet/runtime implementation in System.Net.Security.SecureChannel + var chain = new X509Chain (); + + chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; + chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; + + chain.ChainPolicy.ExtraStore.AddRange (certificates); + + return chain; + } + + private static X509Certificate2[] ConvertCertificates (JavaX509Certificate[] certificates) + => certificates.Select (cert => new X509Certificate2 (cert.GetEncoded ()!)).ToArray (); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg index 914ef686ac2..881353bf906 100644 --- a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg +++ b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg @@ -15,6 +15,7 @@ -keep class opentk_1_0.platform.android.AndroidGameView { *; (...); } -keep class opentk_1_0.GameViewBase { *; (...); } -keep class com.xamarin.java_interop.ManagedPeer { *; (...); } +-keep class xamarin.android.net.X509TrustManagerWithValidationCallback { *; (...); } -keep class android.runtime.** { (...); } -keep class assembly_mono_android.android.runtime.** { (...); } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc index 3cbcb3bb767..11037595fc9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc @@ -5,37 +5,37 @@ "Size": 3032 }, "assemblies/Java.Interop.dll": { - "Size": 55106 + "Size": 55099 }, "assemblies/Mono.Android.dll": { - "Size": 88461 + "Size": 88852 }, "assemblies/rc.bin": { "Size": 1083 }, "assemblies/System.Linq.dll": { - "Size": 10120 + "Size": 10112 }, "assemblies/System.Private.CoreLib.dll": { - "Size": 519314 + "Size": 519255 }, "assemblies/System.Runtime.CompilerServices.Unsafe.dll": { "Size": 1165 }, "assemblies/System.Runtime.dll": { - "Size": 2374 + "Size": 2369 }, "assemblies/UnnamedProject.dll": { - "Size": 3546 + "Size": 3543 }, "classes.dex": { - "Size": 345328 + "Size": 344840 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 382304 + "Size": 382480 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3192432 + "Size": 3176080 }, "lib/arm64-v8a/libSystem.IO.Compression.Native.so": { "Size": 776216 @@ -47,7 +47,7 @@ "Size": 150032 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 9424 + "Size": 9328 }, "META-INF/BNDLTOOL.RSA": { "Size": 1213 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc index 33a48ec8ce0..82b072836e9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleLegacy.apkdesc @@ -5,35 +5,35 @@ "Size": 2604 }, "assemblies/Java.Interop.dll": { - "Size": 67956 + "Size": 67947 }, "assemblies/Mono.Android.dll": { - "Size": 256630 + "Size": 257171 }, "assemblies/mscorlib.dll": { - "Size": 769015 + "Size": 769010 }, "assemblies/System.Core.dll": { - "Size": 28199 + "Size": 28190 }, "assemblies/System.dll": { - "Size": 9180 + "Size": 9178 }, "assemblies/UnnamedProject.dll": { - "Size": 2881 + "Size": 2871 }, "classes.dex": { - "Size": 347796 + "Size": 349528 }, "lib/arm64-v8a/libmono-btls-shared.so": { "Size": 1613872 }, + "lib/arm64-v8a/libmonodroid.so": { + "Size": 296448 + }, "lib/arm64-v8a/libmono-native.so": { "Size": 750976 }, - "lib/arm64-v8a/libmonodroid.so": { - "Size": 296192 - }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 4030448 }, @@ -41,7 +41,7 @@ "Size": 65512 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 19960 + "Size": 19864 }, "META-INF/ANDROIDD.RSA": { "Size": 1213 @@ -74,5 +74,5 @@ "Size": 1724 } }, - "PackageSize": 4011732 + "PackageSize": 4015828 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc index f3acfe04246..aab3f1b77d5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc @@ -5,184 +5,184 @@ "Size": 3568 }, "assemblies/FormsViewGroup.dll": { - "Size": 7247 + "Size": 7240 }, "assemblies/Java.Interop.dll": { - "Size": 62017 + "Size": 62048 }, "assemblies/Mono.Android.dll": { - "Size": 442008 + "Size": 445340 }, "assemblies/mscorlib.dll": { - "Size": 3803 + "Size": 3799 }, "assemblies/netstandard.dll": { - "Size": 5503 + "Size": 5498 }, "assemblies/rc.bin": { "Size": 1083 }, "assemblies/System.Collections.Concurrent.dll": { - "Size": 11230 + "Size": 11226 }, "assemblies/System.Collections.dll": { - "Size": 16741 + "Size": 16734 }, "assemblies/System.Collections.NonGeneric.dll": { - "Size": 8443 + "Size": 8434 }, "assemblies/System.ComponentModel.dll": { - "Size": 1965 + "Size": 1960 }, "assemblies/System.ComponentModel.Primitives.dll": { - "Size": 2569 + "Size": 2563 }, "assemblies/System.ComponentModel.TypeConverter.dll": { - "Size": 5970 + "Size": 5967 }, "assemblies/System.Console.dll": { - "Size": 6532 + "Size": 6526 }, "assemblies/System.Core.dll": { - "Size": 1932 + "Size": 1928 }, "assemblies/System.Diagnostics.TraceSource.dll": { - "Size": 6761 + "Size": 6754 }, "assemblies/System.dll": { - "Size": 2279 + "Size": 2274 }, "assemblies/System.Drawing.dll": { - "Size": 1961 + "Size": 1956 }, "assemblies/System.Drawing.Primitives.dll": { - "Size": 12206 + "Size": 12197 }, "assemblies/System.IO.Compression.dll": { - "Size": 17221 + "Size": 17215 }, "assemblies/System.IO.IsolatedStorage.dll": { - "Size": 10569 + "Size": 10568 }, "assemblies/System.Linq.dll": { - "Size": 19480 + "Size": 19471 }, "assemblies/System.Linq.Expressions.dll": { - "Size": 182084 + "Size": 182073 }, "assemblies/System.Net.Http.dll": { - "Size": 65842 + "Size": 65836 }, "assemblies/System.Net.Primitives.dll": { - "Size": 22368 + "Size": 22364 }, "assemblies/System.Net.Requests.dll": { - "Size": 3734 + "Size": 3728 }, "assemblies/System.ObjectModel.dll": { - "Size": 11974 + "Size": 11967 }, "assemblies/System.Private.CoreLib.dll": { - "Size": 757472 + "Size": 757481 }, "assemblies/System.Private.DataContractSerialization.dll": { - "Size": 191079 + "Size": 191077 }, "assemblies/System.Private.Uri.dll": { - "Size": 43502 + "Size": 43498 }, "assemblies/System.Private.Xml.dll": { - "Size": 220183 + "Size": 220179 }, "assemblies/System.Private.Xml.Linq.dll": { - "Size": 17099 + "Size": 17093 }, "assemblies/System.Runtime.CompilerServices.Unsafe.dll": { "Size": 1216 }, "assemblies/System.Runtime.dll": { - "Size": 2561 + "Size": 2557 }, "assemblies/System.Runtime.Serialization.dll": { - "Size": 1893 + "Size": 1890 }, "assemblies/System.Runtime.Serialization.Formatters.dll": { - "Size": 2637 + "Size": 2630 }, "assemblies/System.Runtime.Serialization.Primitives.dll": { - "Size": 3943 + "Size": 3938 }, "assemblies/System.Security.Cryptography.Algorithms.dll": { - "Size": 6815 + "Size": 6810 }, "assemblies/System.Security.Cryptography.Primitives.dll": { - "Size": 2973 + "Size": 2967 }, "assemblies/System.Text.RegularExpressions.dll": { - "Size": 76702 + "Size": 76701 }, "assemblies/System.Xml.dll": { - "Size": 1782 + "Size": 1781 }, "assemblies/UnnamedProject.dll": { - "Size": 117237 + "Size": 117235 }, "assemblies/Xamarin.AndroidX.Activity.dll": { - "Size": 6069 + "Size": 6068 }, "assemblies/Xamarin.AndroidX.AppCompat.AppCompatResources.dll": { - "Size": 6095 + "Size": 6091 }, "assemblies/Xamarin.AndroidX.AppCompat.dll": { - "Size": 112591 + "Size": 112585 }, "assemblies/Xamarin.AndroidX.CardView.dll": { - "Size": 6810 + "Size": 6804 }, "assemblies/Xamarin.AndroidX.CoordinatorLayout.dll": { - "Size": 16603 + "Size": 16599 }, "assemblies/Xamarin.AndroidX.Core.dll": { - "Size": 96722 + "Size": 96714 }, "assemblies/Xamarin.AndroidX.DrawerLayout.dll": { - "Size": 14271 + "Size": 14267 }, "assemblies/Xamarin.AndroidX.Fragment.dll": { - "Size": 39926 + "Size": 39925 }, "assemblies/Xamarin.AndroidX.Legacy.Support.Core.UI.dll": { - "Size": 6133 + "Size": 6130 }, "assemblies/Xamarin.AndroidX.Lifecycle.Common.dll": { - "Size": 6592 + "Size": 6588 }, "assemblies/Xamarin.AndroidX.Lifecycle.LiveData.Core.dll": { - "Size": 6672 + "Size": 6668 }, "assemblies/Xamarin.AndroidX.Lifecycle.ViewModel.dll": { - "Size": 3272 + "Size": 3269 }, "assemblies/Xamarin.AndroidX.Loader.dll": { - "Size": 12670 + "Size": 12666 }, "assemblies/Xamarin.AndroidX.RecyclerView.dll": { - "Size": 84687 + "Size": 84678 }, "assemblies/Xamarin.AndroidX.SavedState.dll": { - "Size": 5077 + "Size": 5074 }, "assemblies/Xamarin.AndroidX.SwipeRefreshLayout.dll": { - "Size": 10382 + "Size": 10375 }, "assemblies/Xamarin.AndroidX.ViewPager.dll": { - "Size": 17985 + "Size": 17982 }, "assemblies/Xamarin.Forms.Core.dll": { "Size": 528450 }, "assemblies/Xamarin.Forms.Platform.Android.dll": { - "Size": 384997 + "Size": 384995 }, "assemblies/Xamarin.Forms.Platform.dll": { "Size": 56878 @@ -191,16 +191,16 @@ "Size": 60774 }, "assemblies/Xamarin.Google.Android.Material.dll": { - "Size": 40135 + "Size": 40129 }, "classes.dex": { - "Size": 3458288 + "Size": 3457504 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 382304 + "Size": 382480 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3192432 + "Size": 3176080 }, "lib/arm64-v8a/libSystem.IO.Compression.Native.so": { "Size": 776216 @@ -212,7 +212,7 @@ "Size": 150032 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 98624 + "Size": 98640 }, "META-INF/android.support.design_material.version": { "Size": 12 diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc index b4adbbf5847..0e8e59be373 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsLegacy.apkdesc @@ -5,125 +5,125 @@ "Size": 3140 }, "assemblies/FormsViewGroup.dll": { - "Size": 7215 + "Size": 7207 }, "assemblies/Java.Interop.dll": { - "Size": 68921 + "Size": 68912 }, "assemblies/Mono.Android.dll": { - "Size": 567161 + "Size": 568333 }, "assemblies/Mono.Security.dll": { - "Size": 68433 + "Size": 68430 }, "assemblies/mscorlib.dll": { - "Size": 915405 + "Size": 915391 }, "assemblies/System.Core.dll": { - "Size": 164045 + "Size": 164044 }, "assemblies/System.dll": { - "Size": 388864 + "Size": 388860 }, "assemblies/System.Drawing.Common.dll": { - "Size": 12365 + "Size": 12356 }, "assemblies/System.Net.Http.dll": { - "Size": 110642 + "Size": 110637 }, "assemblies/System.Numerics.dll": { - "Size": 15683 + "Size": 15681 }, "assemblies/System.Runtime.Serialization.dll": { - "Size": 186660 + "Size": 186653 }, "assemblies/System.ServiceModel.Internals.dll": { - "Size": 26593 + "Size": 26585 }, "assemblies/System.Xml.dll": { - "Size": 395657 + "Size": 395652 }, "assemblies/UnnamedProject.dll": { - "Size": 116898 + "Size": 116887 }, "assemblies/Xamarin.AndroidX.Activity.dll": { - "Size": 7701 + "Size": 7689 }, "assemblies/Xamarin.AndroidX.AppCompat.AppCompatResources.dll": { - "Size": 6651 + "Size": 6640 }, "assemblies/Xamarin.AndroidX.AppCompat.dll": { - "Size": 125337 + "Size": 125325 }, "assemblies/Xamarin.AndroidX.CardView.dll": { - "Size": 7370 + "Size": 7357 }, "assemblies/Xamarin.AndroidX.CoordinatorLayout.dll": { - "Size": 18280 + "Size": 18264 }, "assemblies/Xamarin.AndroidX.Core.dll": { - "Size": 131939 + "Size": 131924 }, "assemblies/Xamarin.AndroidX.DrawerLayout.dll": { - "Size": 15430 + "Size": 15422 }, "assemblies/Xamarin.AndroidX.Fragment.dll": { - "Size": 43150 + "Size": 43130 }, "assemblies/Xamarin.AndroidX.Legacy.Support.Core.UI.dll": { - "Size": 6716 + "Size": 6708 }, "assemblies/Xamarin.AndroidX.Lifecycle.Common.dll": { - "Size": 7071 + "Size": 7055 }, "assemblies/Xamarin.AndroidX.Lifecycle.LiveData.Core.dll": { - "Size": 7195 + "Size": 7186 }, "assemblies/Xamarin.AndroidX.Lifecycle.ViewModel.dll": { - "Size": 4875 + "Size": 4862 }, "assemblies/Xamarin.AndroidX.Loader.dll": { - "Size": 13589 + "Size": 13578 }, "assemblies/Xamarin.AndroidX.RecyclerView.dll": { - "Size": 102339 + "Size": 102322 }, "assemblies/Xamarin.AndroidX.SavedState.dll": { - "Size": 6283 + "Size": 6265 }, "assemblies/Xamarin.AndroidX.SwipeRefreshLayout.dll": { - "Size": 11270 + "Size": 11261 }, "assemblies/Xamarin.AndroidX.ViewPager.dll": { - "Size": 19429 + "Size": 19415 }, "assemblies/Xamarin.Forms.Core.dll": { - "Size": 524736 + "Size": 524728 }, "assemblies/Xamarin.Forms.Platform.Android.dll": { - "Size": 384876 + "Size": 384861 }, "assemblies/Xamarin.Forms.Platform.dll": { "Size": 56878 }, "assemblies/Xamarin.Forms.Xaml.dll": { - "Size": 55801 + "Size": 55795 }, "assemblies/Xamarin.Google.Android.Material.dll": { - "Size": 43505 + "Size": 43489 }, "classes.dex": { - "Size": 3460636 + "Size": 3461960 }, "lib/arm64-v8a/libmono-btls-shared.so": { "Size": 1613872 }, + "lib/arm64-v8a/libmonodroid.so": { + "Size": 296448 + }, "lib/arm64-v8a/libmono-native.so": { "Size": 750976 }, - "lib/arm64-v8a/libmonodroid.so": { - "Size": 296192 - }, "lib/arm64-v8a/libmonosgen-2.0.so": { "Size": 4030448 }, @@ -131,7 +131,7 @@ "Size": 65512 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 105016 + "Size": 104920 }, "META-INF/android.support.design_material.version": { "Size": 12 @@ -145,10 +145,10 @@ "META-INF/androidx.activity_activity.version": { "Size": 6 }, - "META-INF/androidx.appcompat_appcompat-resources.version": { + "META-INF/androidx.appcompat_appcompat.version": { "Size": 6 }, - "META-INF/androidx.appcompat_appcompat.version": { + "META-INF/androidx.appcompat_appcompat-resources.version": { "Size": 6 }, "META-INF/androidx.arch.core_core-runtime.version": { @@ -196,10 +196,10 @@ "META-INF/androidx.legacy_legacy-support-v4.version": { "Size": 6 }, - "META-INF/androidx.lifecycle_lifecycle-livedata-core.version": { + "META-INF/androidx.lifecycle_lifecycle-livedata.version": { "Size": 6 }, - "META-INF/androidx.lifecycle_lifecycle-livedata.version": { + "META-INF/androidx.lifecycle_lifecycle-livedata-core.version": { "Size": 6 }, "META-INF/androidx.lifecycle_lifecycle-runtime.version": { @@ -235,10 +235,10 @@ "META-INF/androidx.transition_transition.version": { "Size": 6 }, - "META-INF/androidx.vectordrawable_vectordrawable-animated.version": { + "META-INF/androidx.vectordrawable_vectordrawable.version": { "Size": 6 }, - "META-INF/androidx.vectordrawable_vectordrawable.version": { + "META-INF/androidx.vectordrawable_vectordrawable-animated.version": { "Size": 6 }, "META-INF/androidx.versionedparcelable_versionedparcelable.version": { @@ -256,12 +256,6 @@ "META-INF/proguard/androidx-annotations.pro": { "Size": 339 }, - "res/anim-v21/design_bottom_sheet_slide_in.xml": { - "Size": 616 - }, - "res/anim-v21/design_bottom_sheet_slide_out.xml": { - "Size": 616 - }, "res/anim/abc_fade_in.xml": { "Size": 388 }, @@ -358,9 +352,6 @@ "res/anim/exittoright.xml": { "Size": 468 }, - "res/animator-v21/design_appbar_state_list_animator.xml": { - "Size": 1216 - }, "res/animator/design_fab_hide_motion_spec.xml": { "Size": 796 }, @@ -388,38 +379,14 @@ "res/animator/mtrl_fab_transformation_sheet_expand_spec.xml": { "Size": 1888 }, - "res/color-v21/abc_btn_colored_borderless_text_material.xml": { - "Size": 464 - }, - "res/color-v23/abc_btn_colored_borderless_text_material.xml": { - "Size": 500 - }, - "res/color-v23/abc_btn_colored_text_material.xml": { - "Size": 500 - }, - "res/color-v23/abc_color_highlight_material.xml": { - "Size": 544 - }, - "res/color-v23/abc_tint_btn_checkable.xml": { - "Size": 624 - }, - "res/color-v23/abc_tint_default.xml": { - "Size": 1120 - }, - "res/color-v23/abc_tint_edittext.xml": { - "Size": 668 - }, - "res/color-v23/abc_tint_seek_thumb.xml": { - "Size": 500 - }, - "res/color-v23/abc_tint_spinner.xml": { - "Size": 668 + "res/animator-v21/design_appbar_state_list_animator.xml": { + "Size": 1216 }, - "res/color-v23/abc_tint_switch_track.xml": { - "Size": 664 + "res/anim-v21/design_bottom_sheet_slide_in.xml": { + "Size": 616 }, - "res/color-v23/design_tint_password_toggle.xml": { - "Size": 376 + "res/anim-v21/design_bottom_sheet_slide_out.xml": { + "Size": 616 }, "res/color/abc_background_cache_hint_selector_material_dark.xml": { "Size": 468 @@ -523,10 +490,10 @@ "res/color/mtrl_tabs_colored_ripple_color.xml": { "Size": 948 }, - "res/color/mtrl_tabs_icon_color_selector_colored.xml": { + "res/color/mtrl_tabs_icon_color_selector.xml": { "Size": 464 }, - "res/color/mtrl_tabs_icon_color_selector.xml": { + "res/color/mtrl_tabs_icon_color_selector_colored.xml": { "Size": 464 }, "res/color/mtrl_tabs_legacy_text_color_selector.xml": { @@ -544,159 +511,375 @@ "res/color/switch_thumb_material_light.xml": { "Size": 464 }, - "res/drawable-anydpi-v21/design_ic_visibility_off.xml": { - "Size": 1144 - }, - "res/drawable-anydpi-v21/design_ic_visibility.xml": { - "Size": 540 + "res/color-v21/abc_btn_colored_borderless_text_material.xml": { + "Size": 464 }, - "res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png": { - "Size": 272 + "res/color-v23/abc_btn_colored_borderless_text_material.xml": { + "Size": 500 }, - "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_000.png": { - "Size": 227 + "res/color-v23/abc_btn_colored_text_material.xml": { + "Size": 500 }, - "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_015.png": { - "Size": 404 + "res/color-v23/abc_color_highlight_material.xml": { + "Size": 544 }, - "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_000.png": { - "Size": 464 + "res/color-v23/abc_tint_btn_checkable.xml": { + "Size": 624 }, - "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_015.png": { - "Size": 563 + "res/color-v23/abc_tint_default.xml": { + "Size": 1120 }, - "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png": { - "Size": 1096 + "res/color-v23/abc_tint_edittext.xml": { + "Size": 668 }, - "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png": { - "Size": 1243 + "res/color-v23/abc_tint_seek_thumb.xml": { + "Size": 500 }, - "res/drawable-hdpi-v4/abc_cab_background_top_mtrl_alpha.9.png": { - "Size": 226 + "res/color-v23/abc_tint_spinner.xml": { + "Size": 668 }, - "res/drawable-hdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png": { - "Size": 171 + "res/color-v23/abc_tint_switch_track.xml": { + "Size": 664 }, - "res/drawable-hdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png": { - "Size": 202 + "res/color-v23/design_tint_password_toggle.xml": { + "Size": 376 }, - "res/drawable-hdpi-v4/abc_ic_menu_cut_mtrl_alpha.png": { - "Size": 404 + "res/drawable/abc_btn_borderless_material.xml": { + "Size": 588 }, - "res/drawable-hdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png": { - "Size": 226 + "res/drawable/abc_btn_check_material.xml": { + "Size": 464 }, - "res/drawable-hdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png": { - "Size": 215 + "res/drawable/abc_btn_check_material_anim.xml": { + "Size": 816 }, - "res/drawable-hdpi-v4/abc_ic_menu_share_mtrl_alpha.png": { - "Size": 389 + "res/drawable/abc_btn_colored_material.xml": { + "Size": 344 }, - "res/drawable-hdpi-v4/abc_ic_star_black_16dp.png": { - "Size": 263 + "res/drawable/abc_btn_default_mtrl_shape.xml": { + "Size": 932 }, - "res/drawable-hdpi-v4/abc_ic_star_black_36dp.png": { - "Size": 522 + "res/drawable/abc_btn_radio_material.xml": { + "Size": 464 }, - "res/drawable-hdpi-v4/abc_ic_star_black_48dp.png": { - "Size": 668 + "res/drawable/abc_btn_radio_material_anim.xml": { + "Size": 816 }, - "res/drawable-hdpi-v4/abc_ic_star_half_black_16dp.png": { - "Size": 197 + "res/drawable/abc_cab_background_internal_bg.xml": { + "Size": 372 }, - "res/drawable-hdpi-v4/abc_ic_star_half_black_36dp.png": { - "Size": 328 + "res/drawable/abc_cab_background_top_material.xml": { + "Size": 336 }, - "res/drawable-hdpi-v4/abc_ic_star_half_black_48dp.png": { - "Size": 431 + "res/drawable/abc_dialog_material_background.xml": { + "Size": 716 }, - "res/drawable-hdpi-v4/abc_list_divider_mtrl_alpha.9.png": { - "Size": 167 + "res/drawable/abc_edit_text_material.xml": { + "Size": 868 }, - "res/drawable-hdpi-v4/abc_list_focused_holo.9.png": { - "Size": 244 + "res/drawable/abc_ic_ab_back_material.xml": { + "Size": 692 }, - "res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png": { - "Size": 212 + "res/drawable/abc_ic_arrow_drop_right_black_24dp.xml": { + "Size": 1000 }, - "res/drawable-hdpi-v4/abc_list_pressed_holo_dark.9.png": { - "Size": 208 + "res/drawable/abc_ic_clear_material.xml": { + "Size": 684 }, - "res/drawable-hdpi-v4/abc_list_pressed_holo_light.9.png": { - "Size": 208 + "res/drawable/abc_ic_go_search_api_material.xml": { + "Size": 640 }, - "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_dark.9.png": { - "Size": 228 + "res/drawable/abc_ic_menu_overflow_material.xml": { + "Size": 792 }, - "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_light.9.png": { - "Size": 229 + "res/drawable/abc_ic_search_api_material.xml": { + "Size": 812 }, - "res/drawable-hdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png": { - "Size": 738 + "res/drawable/abc_ic_voice_search_api_material.xml": { + "Size": 828 }, - "res/drawable-hdpi-v4/abc_popup_background_mtrl_mult.9.png": { - "Size": 1098 + "res/drawable/abc_item_background_holo_dark.xml": { + "Size": 1012 }, - "res/drawable-hdpi-v4/abc_scrubber_control_off_mtrl_alpha.png": { - "Size": 201 + "res/drawable/abc_item_background_holo_light.xml": { + "Size": 1012 }, - "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png": { - "Size": 196 + "res/drawable/abc_list_divider_material.xml": { + "Size": 480 }, - "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png": { - "Size": 272 + "res/drawable/abc_list_selector_background_transition_holo_dark.xml": { + "Size": 424 }, - "res/drawable-hdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png": { - "Size": 205 + "res/drawable/abc_list_selector_background_transition_holo_light.xml": { + "Size": 424 }, - "res/drawable-hdpi-v4/abc_scrubber_track_mtrl_alpha.9.png": { - "Size": 196 + "res/drawable/abc_list_selector_holo_dark.xml": { + "Size": 1064 }, - "res/drawable-hdpi-v4/abc_spinner_mtrl_am_alpha.9.png": { - "Size": 345 + "res/drawable/abc_list_selector_holo_light.xml": { + "Size": 1064 }, - "res/drawable-hdpi-v4/abc_switch_track_mtrl_alpha.9.png": { - "Size": 484 + "res/drawable/abc_ratingbar_indicator_material.xml": { + "Size": 664 }, - "res/drawable-hdpi-v4/abc_tab_indicator_mtrl_alpha.9.png": { - "Size": 190 + "res/drawable/abc_ratingbar_material.xml": { + "Size": 664 }, - "res/drawable-hdpi-v4/abc_text_select_handle_left_mtrl_dark.png": { - "Size": 278 + "res/drawable/abc_ratingbar_small_material.xml": { + "Size": 664 }, - "res/drawable-hdpi-v4/abc_text_select_handle_left_mtrl_light.png": { - "Size": 278 + "res/drawable/abc_seekbar_thumb_material.xml": { + "Size": 1100 }, - "res/drawable-hdpi-v4/abc_text_select_handle_middle_mtrl_dark.png": { - "Size": 398 + "res/drawable/abc_seekbar_tick_mark_material.xml": { + "Size": 516 }, - "res/drawable-hdpi-v4/abc_text_select_handle_middle_mtrl_light.png": { - "Size": 396 + "res/drawable/abc_seekbar_track_material.xml": { + "Size": 1408 }, - "res/drawable-hdpi-v4/abc_text_select_handle_right_mtrl_dark.png": { - "Size": 263 + "res/drawable/abc_spinner_textfield_background_material.xml": { + "Size": 1160 }, - "res/drawable-hdpi-v4/abc_text_select_handle_right_mtrl_light.png": { - "Size": 262 + "res/drawable/abc_switch_thumb_material.xml": { + "Size": 464 }, - "res/drawable-hdpi-v4/abc_textfield_activated_mtrl_alpha.9.png": { - "Size": 186 + "res/drawable/abc_tab_indicator_material.xml": { + "Size": 468 }, - "res/drawable-hdpi-v4/abc_textfield_default_mtrl_alpha.9.png": { - "Size": 192 + "res/drawable/abc_text_cursor_material.xml": { + "Size": 516 }, - "res/drawable-hdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png": { - "Size": 178 + "res/drawable/abc_textfield_search_material.xml": { + "Size": 756 }, - "res/drawable-hdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { + "res/drawable/abc_vector_test.xml": { + "Size": 612 + }, + "res/drawable/btn_checkbox_checked_mtrl.xml": { + "Size": 2688 + }, + "res/drawable/btn_checkbox_checked_to_unchecked_mtrl_animation.xml": { + "Size": 688 + }, + "res/drawable/btn_checkbox_unchecked_mtrl.xml": { + "Size": 2660 + }, + "res/drawable/btn_checkbox_unchecked_to_checked_mtrl_animation.xml": { + "Size": 688 + }, + "res/drawable/btn_radio_off_mtrl.xml": { + "Size": 1728 + }, + "res/drawable/btn_radio_off_to_on_mtrl_animation.xml": { + "Size": 680 + }, + "res/drawable/btn_radio_on_mtrl.xml": { + "Size": 1656 + }, + "res/drawable/btn_radio_on_to_off_mtrl_animation.xml": { + "Size": 680 + }, + "res/drawable/design_bottom_navigation_item_background.xml": { + "Size": 784 + }, + "res/drawable/design_fab_background.xml": { + "Size": 372 + }, + "res/drawable/design_password_eye.xml": { + "Size": 464 + }, + "res/drawable/design_snackbar_background.xml": { + "Size": 484 + }, + "res/drawable/ic_mtrl_chip_checked_black.xml": { + "Size": 600 + }, + "res/drawable/ic_mtrl_chip_checked_circle.xml": { + "Size": 940 + }, + "res/drawable/ic_mtrl_chip_close_circle.xml": { + "Size": 808 + }, + "res/drawable/mtrl_snackbar_background.xml": { + "Size": 484 + }, + "res/drawable/mtrl_tabs_default_indicator.xml": { + "Size": 628 + }, + "res/drawable/navigation_empty_icon.xml": { + "Size": 516 + }, + "res/drawable/notification_bg.xml": { + "Size": 532 + }, + "res/drawable/notification_bg_low.xml": { + "Size": 532 + }, + "res/drawable/notification_icon_background.xml": { + "Size": 372 + }, + "res/drawable/notification_tile_bg.xml": { + "Size": 304 + }, + "res/drawable/tooltip_frame_dark.xml": { + "Size": 484 + }, + "res/drawable/tooltip_frame_light.xml": { + "Size": 484 + }, + "res/drawable-anydpi-v21/design_ic_visibility.xml": { + "Size": 540 + }, + "res/drawable-anydpi-v21/design_ic_visibility_off.xml": { + "Size": 1144 + }, + "res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png": { + "Size": 272 + }, + "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_000.png": { + "Size": 227 + }, + "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_015.png": { + "Size": 404 + }, + "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_000.png": { + "Size": 464 + }, + "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_015.png": { + "Size": 563 + }, + "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png": { + "Size": 1096 + }, + "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png": { + "Size": 1243 + }, + "res/drawable-hdpi-v4/abc_cab_background_top_mtrl_alpha.9.png": { + "Size": 226 + }, + "res/drawable-hdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png": { + "Size": 171 + }, + "res/drawable-hdpi-v4/abc_ic_menu_copy_mtrl_am_alpha.png": { + "Size": 202 + }, + "res/drawable-hdpi-v4/abc_ic_menu_cut_mtrl_alpha.png": { + "Size": 404 + }, + "res/drawable-hdpi-v4/abc_ic_menu_paste_mtrl_am_alpha.png": { + "Size": 226 + }, + "res/drawable-hdpi-v4/abc_ic_menu_selectall_mtrl_alpha.png": { + "Size": 215 + }, + "res/drawable-hdpi-v4/abc_ic_menu_share_mtrl_alpha.png": { + "Size": 389 + }, + "res/drawable-hdpi-v4/abc_ic_star_black_16dp.png": { + "Size": 263 + }, + "res/drawable-hdpi-v4/abc_ic_star_black_36dp.png": { + "Size": 522 + }, + "res/drawable-hdpi-v4/abc_ic_star_black_48dp.png": { + "Size": 668 + }, + "res/drawable-hdpi-v4/abc_ic_star_half_black_16dp.png": { + "Size": 197 + }, + "res/drawable-hdpi-v4/abc_ic_star_half_black_36dp.png": { + "Size": 328 + }, + "res/drawable-hdpi-v4/abc_ic_star_half_black_48dp.png": { + "Size": 431 + }, + "res/drawable-hdpi-v4/abc_list_divider_mtrl_alpha.9.png": { + "Size": 167 + }, + "res/drawable-hdpi-v4/abc_list_focused_holo.9.png": { + "Size": 244 + }, + "res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png": { + "Size": 212 + }, + "res/drawable-hdpi-v4/abc_list_pressed_holo_dark.9.png": { + "Size": 208 + }, + "res/drawable-hdpi-v4/abc_list_pressed_holo_light.9.png": { + "Size": 208 + }, + "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_dark.9.png": { + "Size": 228 + }, + "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_light.9.png": { + "Size": 229 + }, + "res/drawable-hdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png": { + "Size": 738 + }, + "res/drawable-hdpi-v4/abc_popup_background_mtrl_mult.9.png": { + "Size": 1098 + }, + "res/drawable-hdpi-v4/abc_scrubber_control_off_mtrl_alpha.png": { + "Size": 201 + }, + "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png": { + "Size": 196 + }, + "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png": { + "Size": 272 + }, + "res/drawable-hdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png": { + "Size": 205 + }, + "res/drawable-hdpi-v4/abc_scrubber_track_mtrl_alpha.9.png": { + "Size": 196 + }, + "res/drawable-hdpi-v4/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 345 + }, + "res/drawable-hdpi-v4/abc_switch_track_mtrl_alpha.9.png": { + "Size": 484 + }, + "res/drawable-hdpi-v4/abc_tab_indicator_mtrl_alpha.9.png": { + "Size": 190 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_left_mtrl_dark.png": { + "Size": 278 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_left_mtrl_light.png": { + "Size": 278 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_middle_mtrl_dark.png": { + "Size": 398 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_middle_mtrl_light.png": { + "Size": 396 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_right_mtrl_dark.png": { + "Size": 263 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_right_mtrl_light.png": { + "Size": 262 + }, + "res/drawable-hdpi-v4/abc_textfield_activated_mtrl_alpha.9.png": { + "Size": 186 + }, + "res/drawable-hdpi-v4/abc_textfield_default_mtrl_alpha.9.png": { + "Size": 192 + }, + "res/drawable-hdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png": { "Size": 178 }, - "res/drawable-hdpi-v4/design_ic_visibility_off.png": { - "Size": 507 + "res/drawable-hdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { + "Size": 178 }, "res/drawable-hdpi-v4/design_ic_visibility.png": { "Size": 470 }, + "res/drawable-hdpi-v4/design_ic_visibility_off.png": { + "Size": 507 + }, "res/drawable-hdpi-v4/icon.png": { "Size": 4762 }, @@ -706,12 +889,12 @@ "res/drawable-hdpi-v4/notification_bg_low_pressed.9.png": { "Size": 225 }, - "res/drawable-hdpi-v4/notification_bg_normal_pressed.9.png": { - "Size": 225 - }, "res/drawable-hdpi-v4/notification_bg_normal.9.png": { "Size": 212 }, + "res/drawable-hdpi-v4/notification_bg_normal_pressed.9.png": { + "Size": 225 + }, "res/drawable-hdpi-v4/notify_panel_notification_icon_bg.png": { "Size": 107 }, @@ -901,12 +1084,12 @@ "res/drawable-mdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { "Size": 178 }, - "res/drawable-mdpi-v4/design_ic_visibility_off.png": { - "Size": 351 - }, "res/drawable-mdpi-v4/design_ic_visibility.png": { "Size": 309 }, + "res/drawable-mdpi-v4/design_ic_visibility_off.png": { + "Size": 351 + }, "res/drawable-mdpi-v4/icon.png": { "Size": 2200 }, @@ -916,12 +1099,12 @@ "res/drawable-mdpi-v4/notification_bg_low_pressed.9.png": { "Size": 223 }, - "res/drawable-mdpi-v4/notification_bg_normal_pressed.9.png": { - "Size": 223 - }, "res/drawable-mdpi-v4/notification_bg_normal.9.png": { "Size": 215 }, + "res/drawable-mdpi-v4/notification_bg_normal_pressed.9.png": { + "Size": 223 + }, "res/drawable-mdpi-v4/notify_panel_notification_icon_bg.png": { "Size": 98 }, @@ -1129,12 +1312,12 @@ "res/drawable-xhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { "Size": 182 }, - "res/drawable-xhdpi-v4/design_ic_visibility_off.png": { - "Size": 629 - }, "res/drawable-xhdpi-v4/design_ic_visibility.png": { "Size": 593 }, + "res/drawable-xhdpi-v4/design_ic_visibility_off.png": { + "Size": 629 + }, "res/drawable-xhdpi-v4/icon.png": { "Size": 7462 }, @@ -1144,12 +1327,12 @@ "res/drawable-xhdpi-v4/notification_bg_low_pressed.9.png": { "Size": 252 }, - "res/drawable-xhdpi-v4/notification_bg_normal_pressed.9.png": { - "Size": 247 - }, "res/drawable-xhdpi-v4/notification_bg_normal.9.png": { "Size": 221 }, + "res/drawable-xhdpi-v4/notification_bg_normal_pressed.9.png": { + "Size": 247 + }, "res/drawable-xhdpi-v4/notify_panel_notification_icon_bg.png": { "Size": 138 }, @@ -1294,12 +1477,12 @@ "res/drawable-xxhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { "Size": 186 }, - "res/drawable-xxhdpi-v4/design_ic_visibility_off.png": { - "Size": 884 - }, "res/drawable-xxhdpi-v4/design_ic_visibility.png": { "Size": 868 }, + "res/drawable-xxhdpi-v4/design_ic_visibility_off.png": { + "Size": 884 + }, "res/drawable-xxhdpi-v4/icon.png": { "Size": 13092 }, @@ -1381,207 +1564,15 @@ "res/drawable-xxxhdpi-v4/abc_text_select_handle_right_mtrl_light.png": { "Size": 513 }, - "res/drawable-xxxhdpi-v4/design_ic_visibility_off.png": { - "Size": 1201 - }, "res/drawable-xxxhdpi-v4/design_ic_visibility.png": { "Size": 1155 }, + "res/drawable-xxxhdpi-v4/design_ic_visibility_off.png": { + "Size": 1201 + }, "res/drawable-xxxhdpi-v4/icon.png": { "Size": 20118 }, - "res/drawable/abc_btn_borderless_material.xml": { - "Size": 588 - }, - "res/drawable/abc_btn_check_material_anim.xml": { - "Size": 816 - }, - "res/drawable/abc_btn_check_material.xml": { - "Size": 464 - }, - "res/drawable/abc_btn_colored_material.xml": { - "Size": 344 - }, - "res/drawable/abc_btn_default_mtrl_shape.xml": { - "Size": 932 - }, - "res/drawable/abc_btn_radio_material_anim.xml": { - "Size": 816 - }, - "res/drawable/abc_btn_radio_material.xml": { - "Size": 464 - }, - "res/drawable/abc_cab_background_internal_bg.xml": { - "Size": 372 - }, - "res/drawable/abc_cab_background_top_material.xml": { - "Size": 336 - }, - "res/drawable/abc_dialog_material_background.xml": { - "Size": 716 - }, - "res/drawable/abc_edit_text_material.xml": { - "Size": 868 - }, - "res/drawable/abc_ic_ab_back_material.xml": { - "Size": 692 - }, - "res/drawable/abc_ic_arrow_drop_right_black_24dp.xml": { - "Size": 1000 - }, - "res/drawable/abc_ic_clear_material.xml": { - "Size": 684 - }, - "res/drawable/abc_ic_go_search_api_material.xml": { - "Size": 640 - }, - "res/drawable/abc_ic_menu_overflow_material.xml": { - "Size": 792 - }, - "res/drawable/abc_ic_search_api_material.xml": { - "Size": 812 - }, - "res/drawable/abc_ic_voice_search_api_material.xml": { - "Size": 828 - }, - "res/drawable/abc_item_background_holo_dark.xml": { - "Size": 1012 - }, - "res/drawable/abc_item_background_holo_light.xml": { - "Size": 1012 - }, - "res/drawable/abc_list_divider_material.xml": { - "Size": 480 - }, - "res/drawable/abc_list_selector_background_transition_holo_dark.xml": { - "Size": 424 - }, - "res/drawable/abc_list_selector_background_transition_holo_light.xml": { - "Size": 424 - }, - "res/drawable/abc_list_selector_holo_dark.xml": { - "Size": 1064 - }, - "res/drawable/abc_list_selector_holo_light.xml": { - "Size": 1064 - }, - "res/drawable/abc_ratingbar_indicator_material.xml": { - "Size": 664 - }, - "res/drawable/abc_ratingbar_material.xml": { - "Size": 664 - }, - "res/drawable/abc_ratingbar_small_material.xml": { - "Size": 664 - }, - "res/drawable/abc_seekbar_thumb_material.xml": { - "Size": 1100 - }, - "res/drawable/abc_seekbar_tick_mark_material.xml": { - "Size": 516 - }, - "res/drawable/abc_seekbar_track_material.xml": { - "Size": 1408 - }, - "res/drawable/abc_spinner_textfield_background_material.xml": { - "Size": 1160 - }, - "res/drawable/abc_switch_thumb_material.xml": { - "Size": 464 - }, - "res/drawable/abc_tab_indicator_material.xml": { - "Size": 468 - }, - "res/drawable/abc_text_cursor_material.xml": { - "Size": 516 - }, - "res/drawable/abc_textfield_search_material.xml": { - "Size": 756 - }, - "res/drawable/abc_vector_test.xml": { - "Size": 612 - }, - "res/drawable/btn_checkbox_checked_mtrl.xml": { - "Size": 2688 - }, - "res/drawable/btn_checkbox_checked_to_unchecked_mtrl_animation.xml": { - "Size": 688 - }, - "res/drawable/btn_checkbox_unchecked_mtrl.xml": { - "Size": 2660 - }, - "res/drawable/btn_checkbox_unchecked_to_checked_mtrl_animation.xml": { - "Size": 688 - }, - "res/drawable/btn_radio_off_mtrl.xml": { - "Size": 1728 - }, - "res/drawable/btn_radio_off_to_on_mtrl_animation.xml": { - "Size": 680 - }, - "res/drawable/btn_radio_on_mtrl.xml": { - "Size": 1656 - }, - "res/drawable/btn_radio_on_to_off_mtrl_animation.xml": { - "Size": 680 - }, - "res/drawable/design_bottom_navigation_item_background.xml": { - "Size": 784 - }, - "res/drawable/design_fab_background.xml": { - "Size": 372 - }, - "res/drawable/design_password_eye.xml": { - "Size": 464 - }, - "res/drawable/design_snackbar_background.xml": { - "Size": 484 - }, - "res/drawable/ic_mtrl_chip_checked_black.xml": { - "Size": 600 - }, - "res/drawable/ic_mtrl_chip_checked_circle.xml": { - "Size": 940 - }, - "res/drawable/ic_mtrl_chip_close_circle.xml": { - "Size": 808 - }, - "res/drawable/mtrl_snackbar_background.xml": { - "Size": 484 - }, - "res/drawable/mtrl_tabs_default_indicator.xml": { - "Size": 628 - }, - "res/drawable/navigation_empty_icon.xml": { - "Size": 516 - }, - "res/drawable/notification_bg_low.xml": { - "Size": 532 - }, - "res/drawable/notification_bg.xml": { - "Size": 532 - }, - "res/drawable/notification_icon_background.xml": { - "Size": 372 - }, - "res/drawable/notification_tile_bg.xml": { - "Size": 304 - }, - "res/drawable/tooltip_frame_dark.xml": { - "Size": 484 - }, - "res/drawable/tooltip_frame_light.xml": { - "Size": 484 - }, - "res/interpolator-v21/mtrl_fast_out_linear_in.xml": { - "Size": 400 - }, - "res/interpolator-v21/mtrl_fast_out_slow_in.xml": { - "Size": 400 - }, - "res/interpolator-v21/mtrl_linear_out_slow_in.xml": { - "Size": 400 - }, "res/interpolator/btn_checkbox_checked_mtrl_animation_interpolator_0.xml": { "Size": 316 }, @@ -1609,53 +1600,20 @@ "res/interpolator/mtrl_fast_out_slow_in.xml": { "Size": 144 }, - "res/interpolator/mtrl_linear_out_slow_in.xml": { - "Size": 136 - }, "res/interpolator/mtrl_linear.xml": { "Size": 132 }, - "res/layout-sw600dp-v13/design_layout_snackbar.xml": { - "Size": 528 - }, - "res/layout-sw600dp-v13/mtrl_layout_snackbar.xml": { - "Size": 528 - }, - "res/layout-v16/notification_template_custom_big.xml": { - "Size": 3208 - }, - "res/layout-v21/abc_screen_toolbar.xml": { - "Size": 1504 - }, - "res/layout-v21/fallbacktoolbardonotuse.xml": { - "Size": 496 - }, - "res/layout-v21/notification_action_tombstone.xml": { - "Size": 1228 - }, - "res/layout-v21/notification_action.xml": { - "Size": 1052 - }, - "res/layout-v21/notification_template_custom_big.xml": { - "Size": 2456 - }, - "res/layout-v21/notification_template_icon_group.xml": { - "Size": 988 - }, - "res/layout-v21/toolbar.xml": { - "Size": 496 - }, - "res/layout-v22/abc_alert_dialog_button_bar_material.xml": { - "Size": 1584 + "res/interpolator/mtrl_linear_out_slow_in.xml": { + "Size": 136 }, - "res/layout-v26/abc_screen_toolbar.xml": { - "Size": 1560 + "res/interpolator-v21/mtrl_fast_out_linear_in.xml": { + "Size": 400 }, - "res/layout-watch-v20/abc_alert_dialog_button_bar_material.xml": { - "Size": 1208 + "res/interpolator-v21/mtrl_fast_out_slow_in.xml": { + "Size": 400 }, - "res/layout-watch-v20/abc_alert_dialog_title_material.xml": { - "Size": 1352 + "res/interpolator-v21/mtrl_linear_out_slow_in.xml": { + "Size": 400 }, "res/layout/abc_action_bar_title_item.xml": { "Size": 872 @@ -1675,12 +1633,12 @@ "res/layout/abc_action_mode_close_item_material.xml": { "Size": 840 }, - "res/layout/abc_activity_chooser_view_list_item.xml": { - "Size": 1304 - }, "res/layout/abc_activity_chooser_view.xml": { "Size": 1684 }, + "res/layout/abc_activity_chooser_view_list_item.xml": { + "Size": 1304 + }, "res/layout/abc_alert_dialog_button_bar_material.xml": { "Size": 1536 }, @@ -1720,12 +1678,12 @@ "res/layout/abc_screen_content_include.xml": { "Size": 548 }, - "res/layout/abc_screen_simple_overlay_action_mode.xml": { - "Size": 792 - }, "res/layout/abc_screen_simple.xml": { "Size": 832 }, + "res/layout/abc_screen_simple_overlay_action_mode.xml": { + "Size": 792 + }, "res/layout/abc_screen_toolbar.xml": { "Size": 1452 }, @@ -1759,12 +1717,12 @@ "res/layout/design_bottom_sheet_dialog.xml": { "Size": 1184 }, - "res/layout/design_layout_snackbar_include.xml": { - "Size": 1444 - }, "res/layout/design_layout_snackbar.xml": { "Size": 528 }, + "res/layout/design_layout_snackbar_include.xml": { + "Size": 1444 + }, "res/layout/design_layout_tab_icon.xml": { "Size": 408 }, @@ -1774,6 +1732,9 @@ "res/layout/design_menu_item_action_area.xml": { "Size": 320 }, + "res/layout/design_navigation_item.xml": { + "Size": 536 + }, "res/layout/design_navigation_item_header.xml": { "Size": 440 }, @@ -1783,15 +1744,12 @@ "res/layout/design_navigation_item_subheader.xml": { "Size": 564 }, - "res/layout/design_navigation_item.xml": { - "Size": 536 + "res/layout/design_navigation_menu.xml": { + "Size": 528 }, "res/layout/design_navigation_menu_item.xml": { "Size": 856 }, - "res/layout/design_navigation_menu.xml": { - "Size": 528 - }, "res/layout/design_text_input_password_icon.xml": { "Size": 564 }, @@ -1807,35 +1765,35 @@ "res/layout/main.xml": { "Size": 544 }, - "res/layout/mtrl_layout_snackbar_include.xml": { - "Size": 1404 - }, "res/layout/mtrl_layout_snackbar.xml": { "Size": 528 }, - "res/layout/notification_action_tombstone.xml": { - "Size": 1332 + "res/layout/mtrl_layout_snackbar_include.xml": { + "Size": 1404 }, "res/layout/notification_action.xml": { "Size": 1156 }, + "res/layout/notification_action_tombstone.xml": { + "Size": 1332 + }, "res/layout/notification_media_action.xml": { "Size": 564 }, "res/layout/notification_media_cancel_action.xml": { "Size": 744 }, + "res/layout/notification_template_big_media.xml": { + "Size": 1696 + }, "res/layout/notification_template_big_media_custom.xml": { "Size": 3044 }, - "res/layout/notification_template_big_media_narrow_custom.xml": { - "Size": 3216 - }, "res/layout/notification_template_big_media_narrow.xml": { "Size": 1824 }, - "res/layout/notification_template_big_media.xml": { - "Size": 1696 + "res/layout/notification_template_big_media_narrow_custom.xml": { + "Size": 3216 }, "res/layout/notification_template_icon_group.xml": { "Size": 392 @@ -1843,12 +1801,12 @@ "res/layout/notification_template_lines_media.xml": { "Size": 2872 }, - "res/layout/notification_template_media_custom.xml": { - "Size": 2756 - }, "res/layout/notification_template_media.xml": { "Size": 1292 }, + "res/layout/notification_template_media_custom.xml": { + "Size": 2756 + }, "res/layout/notification_template_part_chronometer.xml": { "Size": 440 }, @@ -1879,6 +1837,48 @@ "res/layout/toolbar.xml": { "Size": 452 }, + "res/layout-sw600dp-v13/design_layout_snackbar.xml": { + "Size": 528 + }, + "res/layout-sw600dp-v13/mtrl_layout_snackbar.xml": { + "Size": 528 + }, + "res/layout-v16/notification_template_custom_big.xml": { + "Size": 3208 + }, + "res/layout-v21/abc_screen_toolbar.xml": { + "Size": 1504 + }, + "res/layout-v21/fallbacktoolbardonotuse.xml": { + "Size": 496 + }, + "res/layout-v21/notification_action.xml": { + "Size": 1052 + }, + "res/layout-v21/notification_action_tombstone.xml": { + "Size": 1228 + }, + "res/layout-v21/notification_template_custom_big.xml": { + "Size": 2456 + }, + "res/layout-v21/notification_template_icon_group.xml": { + "Size": 988 + }, + "res/layout-v21/toolbar.xml": { + "Size": 496 + }, + "res/layout-v22/abc_alert_dialog_button_bar_material.xml": { + "Size": 1584 + }, + "res/layout-v26/abc_screen_toolbar.xml": { + "Size": 1560 + }, + "res/layout-watch-v20/abc_alert_dialog_button_bar_material.xml": { + "Size": 1208 + }, + "res/layout-watch-v20/abc_alert_dialog_title_material.xml": { + "Size": 1352 + }, "resources.arsc": { "Size": 341040 } diff --git a/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems b/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems index f0f471e85b4..9881054e160 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems +++ b/tests/Mono.Android-Tests/Mono.Android-Test.Shared.projitems @@ -47,6 +47,7 @@ + diff --git a/tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidClientHandlerTests.cs b/tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidClientHandlerTests.cs index f6b344744c4..361adc860eb 100644 --- a/tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidClientHandlerTests.cs +++ b/tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidClientHandlerTests.cs @@ -283,76 +283,67 @@ public void Redirect_POST_With_Content_Works () Assert.AreEqual (redirectedURI, response.RequestMessage.RequestUri, "Invalid redirected URI"); } } + } - [TestFixture] - public class AndroidClientHandlerTests : AndroidHandlerTestBase + [TestFixture] + public class AndroidClientHandlerTests : AndroidHandlerTestBase + { + protected override HttpMessageHandler CreateHandler () { - protected override HttpMessageHandler CreateHandler () - { - return new AndroidClientHandler (); - } - - [Test] - public void Properties_Defaults () - { - var h = new AndroidClientHandler (); - - Assert.IsTrue (h.AllowAutoRedirect, "#1"); - Assert.AreEqual (DecompressionMethods.None, h.AutomaticDecompression, "#2"); - Assert.AreEqual (0, h.CookieContainer.Count, "#3"); - Assert.AreEqual (4096, h.CookieContainer.MaxCookieSize, "#3b"); - Assert.AreEqual (null, h.Credentials, "#4"); - Assert.AreEqual (50, h.MaxAutomaticRedirections, "#5"); - Assert.IsFalse (h.PreAuthenticate, "#7"); - Assert.IsNull (h.Proxy, "#8"); - Assert.IsTrue (h.SupportsAutomaticDecompression, "#9"); - Assert.IsTrue (h.SupportsProxy, "#10"); - Assert.IsTrue (h.SupportsRedirectConfiguration, "#11"); - Assert.IsTrue (h.UseCookies, "#12"); - Assert.IsFalse (h.UseDefaultCredentials, "#13"); - Assert.IsTrue (h.UseProxy, "#14"); - Assert.AreEqual (ClientCertificateOption.Manual, h.ClientCertificateOptions, "#15"); - Assert.IsNull (h.ServerCertificateCustomValidationCallback, "#16"); - } + return new AndroidClientHandler (); + } - [Test] - public void Properties_Invalid () - { - var h = new AndroidClientHandler (); + [Test] + public void Properties_Defaults () + { + var h = new AndroidClientHandler (); + + Assert.IsTrue (h.AllowAutoRedirect, "#1"); + Assert.AreEqual (DecompressionMethods.None, h.AutomaticDecompression, "#2"); + Assert.AreEqual (0, h.CookieContainer.Count, "#3"); + Assert.AreEqual (4096, h.CookieContainer.MaxCookieSize, "#3b"); + Assert.AreEqual (null, h.Credentials, "#4"); + Assert.AreEqual (50, h.MaxAutomaticRedirections, "#5"); + Assert.IsFalse (h.PreAuthenticate, "#7"); + Assert.IsNull (h.Proxy, "#8"); + Assert.IsTrue (h.SupportsAutomaticDecompression, "#9"); + Assert.IsTrue (h.SupportsProxy, "#10"); + Assert.IsTrue (h.SupportsRedirectConfiguration, "#11"); + Assert.IsTrue (h.UseCookies, "#12"); + Assert.IsFalse (h.UseDefaultCredentials, "#13"); + Assert.IsTrue (h.UseProxy, "#14"); + Assert.AreEqual (ClientCertificateOption.Manual, h.ClientCertificateOptions, "#15"); + Assert.IsNull (h.ServerCertificateCustomValidationCallback, "#16"); + } - try { - h.MaxAutomaticRedirections = 0; - Assert.Fail ("#1"); - } catch (ArgumentOutOfRangeException) { - } + [Test] + public void Properties_Invalid () + { + var h = new AndroidClientHandler (); - try { - h.MaxRequestContentBufferSize = -1; - Assert.Fail ("#2"); - } catch (ArgumentOutOfRangeException) { - } + try { + h.MaxAutomaticRedirections = 0; + Assert.Fail ("#1"); + } catch (ArgumentOutOfRangeException) { } - [Test] - public void Properties_AfterClientCreation () - { - var h = new AndroidClientHandler (); - - h.AllowAutoRedirect = true; - - // We may modify properties after creating the HttpClient. - using (var c = new HttpClient (h, true)) { - h.AllowAutoRedirect = false; - } + try { + h.MaxRequestContentBufferSize = -1; + Assert.Fail ("#2"); + } catch (ArgumentOutOfRangeException) { } } - [TestFixture] - public class AndroidMessageHandlerTests : AndroidHandlerTestBase + [Test] + public void Properties_AfterClientCreation () { - protected override HttpMessageHandler CreateHandler () - { - return new AndroidMessageHandler (); + var h = new AndroidClientHandler (); + + h.AllowAutoRedirect = true; + + // We may modify properties after creating the HttpClient. + using (var c = new HttpClient (h, true)) { + h.AllowAutoRedirect = false; } } } diff --git a/tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs b/tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs new file mode 100644 index 00000000000..8717dad52b9 --- /dev/null +++ b/tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs @@ -0,0 +1,99 @@ +using System; +using System.Net.Http; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; + +using Xamarin.Android.Net; + +using NUnit.Framework; + +namespace Xamarin.Android.NetTests +{ + [TestFixture] + public class AndroidMessageHandlerTests : AndroidHandlerTestBase + { + protected override HttpMessageHandler CreateHandler () + { + return new AndroidMessageHandler (); + } + + [Test] + public async Task ServerCertificateCustomValidationCallback_ApproveRequest () + { + bool callbackHasBeenCalled = false; + + var handler = new AndroidMessageHandler { + ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { + Assert.NotNull (request, "request"); + Assert.AreEqual ("microsoft.com", request.RequestUri.Host); + Assert.NotNull (cert, "cert"); + Assert.True (cert!.Subject.Contains ("microsoft.com"), $"Unexpected certificate subject {cert!.Subject}"); + Assert.True (cert!.Issuer.Contains ("Microsoft"), $"Unexpected certificate issuer {cert!.Issuer}"); + Assert.NotNull (chain, "chain"); + Assert.AreEqual (SslPolicyErrors.None, errors); + + callbackHasBeenCalled = true; + return true; + } + }; + + var client = new HttpClient (handler); + await client.GetStringAsync ("https://microsoft.com/"); + + Assert.IsTrue (callbackHasBeenCalled, "custom validation callback hasn't been called"); + } + + [Test] + public async Task ServerCertificateCustomValidationCallback_RejectRequest () + { + bool callbackHasBeenCalled = false; + bool exceptionWasThrown = false; + + var handler = new AndroidMessageHandler { + ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { + callbackHasBeenCalled = true; + return false; + } + }; + + var client = new HttpClient (handler); + + try { + await client.GetStringAsync ("https://microsoft.com/"); + } catch { + // System.Net.WebException is thrown in Debug mode + // Java.Security.Cert.CertificateException is thrown in Release mode + exceptionWasThrown = true; + } + + Assert.IsTrue (callbackHasBeenCalled, "custom validation callback hasn't been called"); + Assert.IsTrue (exceptionWasThrown, "validation callback hasn't rejected the request"); + } + + [Test] + public async Task ServerCertificateCustomValidationCallback_ApprovesRequestWithInvalidCertificate () + { + bool callbackHasBeenCalled = false; + Exception? exception = null; + + var handler = new AndroidMessageHandler { + ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { + callbackHasBeenCalled = true; + return true; + } + }; + + var client = new HttpClient (handler); + + try { + await client.GetStringAsync ("https://self-signed.badssl.com/"); + } catch (Exception e) { + exception = e; + } + + Assert.IsTrue (callbackHasBeenCalled, "custom validation callback hasn't been called"); + Assert.IsNull (exception, $"an exception was thrown: {exception}"); + } + } +}