From 0175072fb6730ebdbbc75cf931be07607bf02796 Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Thu, 3 Dec 2020 11:01:00 -0800 Subject: [PATCH 01/11] Implement the new ConnectivityManager.NetworkCallback for N+ --- .../Connectivity/Connectivity.android.cs | 74 ++++++++++++++++++- .../Platform/Platform.android.cs | 2 + 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/Xamarin.Essentials/Connectivity/Connectivity.android.cs b/Xamarin.Essentials/Connectivity/Connectivity.android.cs index 40909ea86..21123f6c2 100644 --- a/Xamarin.Essentials/Connectivity/Connectivity.android.cs +++ b/Xamarin.Essentials/Connectivity/Connectivity.android.cs @@ -11,22 +11,46 @@ namespace Xamarin.Essentials public partial class Connectivity { static ConnectivityBroadcastReceiver conectivityReceiver; + static Intent connectivityIntent = new Intent(Platform.EssentialsConnectivityChanged); + static EssentialsNetworkCallback networkCallback; static void StartListeners() { Permissions.EnsureDeclared(); - conectivityReceiver = new ConnectivityBroadcastReceiver(OnConnectivityChanged); + var filter = new IntentFilter(); + if (Platform.HasApiLevelN) + { + RegisterNetworkCallback(); + filter.AddAction(Platform.EssentialsConnectivityChanged); + } + else + { #pragma warning disable CS0618 // Type or member is obsolete - Platform.AppContext.RegisterReceiver(conectivityReceiver, new IntentFilter(ConnectivityManager.ConnectivityAction)); + filter.AddAction(ConnectivityManager.ConnectivityAction); #pragma warning restore CS0618 // Type or member is obsolete + } + + conectivityReceiver = new ConnectivityBroadcastReceiver(OnConnectivityChanged); + + Platform.AppContext.RegisterReceiver(conectivityReceiver, filter); } static void StopListeners() { if (conectivityReceiver == null) return; + + try + { + UnregisterNetworkCallback(); + } + catch + { + Debug.WriteLine("Connectivity receiver already unregistered. Disposing of it."); + } + try { Platform.AppContext.UnregisterReceiver(conectivityReceiver); @@ -39,6 +63,50 @@ static void StopListeners() conectivityReceiver = null; } + static void RegisterNetworkCallback() + { + if (!Platform.HasApiLevelN) + return; + + var manager = Platform.ConnectivityManager; + if (manager == null) + return; + + var request = new NetworkRequest.Builder().Build(); + networkCallback = new EssentialsNetworkCallback(); + manager.RegisterNetworkCallback(request, networkCallback); + } + + static void UnregisterNetworkCallback() + { + if (!Platform.HasApiLevelN) + return; + + var manager = Platform.ConnectivityManager; + if (manager == null || networkCallback == null) + return; + + manager.UnregisterNetworkCallback(networkCallback); + + networkCallback?.Dispose(); + networkCallback = null; + } + + class EssentialsNetworkCallback : ConnectivityManager.NetworkCallback + { + public override void OnAvailable(Network network) => Platform.AppContext.SendBroadcast(connectivityIntent); + + public override void OnLost(Network network) => Platform.AppContext.SendBroadcast(connectivityIntent); + + public override void OnCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) => Platform.AppContext.SendBroadcast(connectivityIntent); + + public override void OnUnavailable() => Platform.AppContext.SendBroadcast(connectivityIntent); + + public override void OnLinkPropertiesChanged(Network network, LinkProperties linkProperties) => Platform.AppContext.SendBroadcast(connectivityIntent); + + public override void OnLosing(Network network, int maxMsToLive) => Platform.AppContext.SendBroadcast(connectivityIntent); + } + static NetworkAccess IsBetterAccess(NetworkAccess currentAccess, NetworkAccess newAccess) => newAccess > currentAccess ? newAccess : currentAccess; @@ -245,7 +313,7 @@ public ConnectivityBroadcastReceiver(Action onChanged) => public override async void OnReceive(Context context, Intent intent) { #pragma warning disable CS0618 // Type or member is obsolete - if (intent.Action != ConnectivityManager.ConnectivityAction) + if (intent.Action != ConnectivityManager.ConnectivityAction && intent.Action != Platform.EssentialsConnectivityChanged) #pragma warning restore CS0618 // Type or member is obsolete return; diff --git a/Xamarin.Essentials/Platform/Platform.android.cs b/Xamarin.Essentials/Platform/Platform.android.cs index 12ea7e397..074da7c72 100644 --- a/Xamarin.Essentials/Platform/Platform.android.cs +++ b/Xamarin.Essentials/Platform/Platform.android.cs @@ -27,6 +27,8 @@ public static partial class Platform public static event EventHandler ActivityStateChanged; + internal const string EssentialsConnectivityChanged = "com.xamarin.essentials.ESSENTIALS_CONNECTIVITY_CHANGED"; + internal const int requestCodeFilePicker = 11001; internal const int requestCodeMediaPicker = 11002; internal const int requestCodeMediaCapture = 11003; From 82038f8ed960cca5667e52e84c1baf49b4c73613 Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Tue, 13 Apr 2021 13:21:47 -0700 Subject: [PATCH 02/11] Fixed #1355 delay processing change so OS updates --- Xamarin.Essentials/DeviceDisplay/DeviceDisplay.android.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Xamarin.Essentials/DeviceDisplay/DeviceDisplay.android.cs b/Xamarin.Essentials/DeviceDisplay/DeviceDisplay.android.cs index e733b7db2..c81f13665 100644 --- a/Xamarin.Essentials/DeviceDisplay/DeviceDisplay.android.cs +++ b/Xamarin.Essentials/DeviceDisplay/DeviceDisplay.android.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Android.Content; using Android.Content.Res; using Android.Provider; @@ -105,6 +106,10 @@ class Listener : OrientationEventListener internal Listener(Context context, Action handler) : base(context) => onChanged = handler; - public override void OnOrientationChanged(int orientation) => onChanged(); + public override async void OnOrientationChanged(int orientation) + { + await Task.Delay(500); + onChanged(); + } } } From fa41d13f46e61b8db3588069068b97c44158ece8 Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Mon, 19 Jul 2021 14:24:23 -0700 Subject: [PATCH 03/11] Update LocationExtensions.ios.tvos.watchos.macos.cs Fixes #1856 --- .../Types/LocationExtensions.ios.tvos.watchos.macos.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs b/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs index 01d52c2db..cfdf74fa3 100644 --- a/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs +++ b/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs @@ -33,7 +33,7 @@ internal static Location ToLocation(this CLLocation location) => Accuracy = location.HorizontalAccuracy, VerticalAccuracy = location.VerticalAccuracy, Timestamp = location.Timestamp.ToDateTime(), -#if __iOS__ || __WATCHOS__ +#if __IOS__ || __WATCHOS__ Course = location.Course < 0 ? default(double?) : location.Course, Speed = location.Speed < 0 ? default(double?) : location.Speed, #endif From 98a69b15655c7e741dc22e6c95fd24440607123f Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Thu, 7 Oct 2021 14:43:22 -0700 Subject: [PATCH 04/11] Set the PopoverPresentationController for files too Fixes #1896 --- Xamarin.Essentials/Share/Share.ios.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xamarin.Essentials/Share/Share.ios.cs b/Xamarin.Essentials/Share/Share.ios.cs index 6d40e5cd6..162415527 100644 --- a/Xamarin.Essentials/Share/Share.ios.cs +++ b/Xamarin.Essentials/Share/Share.ios.cs @@ -58,7 +58,7 @@ static Task PlatformRequestAsync(ShareMultipleFilesRequest request) { activityController.PopoverPresentationController.SourceView = vc.View; - if (request.PresentationSourceBounds != Rectangle.Empty) + if (request.PresentationSourceBounds != Rectangle.Empty || Platform.HasOSVersion(13, 0)) activityController.PopoverPresentationController.SourceRect = request.PresentationSourceBounds.ToPlatformRectangle(); } From f1d8177499fc458ca36c8b9abaa03bddedf32b67 Mon Sep 17 00:00:00 2001 From: Allan Ritchie Date: Mon, 6 Dec 2021 21:45:36 -0500 Subject: [PATCH 05/11] Fix #1912 - if coarse is provided instead of fine location, returned restricted, not denied --- .../Permissions/Permissions.android.cs | 111 +++++++++++------- 1 file changed, 71 insertions(+), 40 deletions(-) diff --git a/Xamarin.Essentials/Permissions/Permissions.android.cs b/Xamarin.Essentials/Permissions/Permissions.android.cs index f8afa8f69..3fb5029cb 100644 --- a/Xamarin.Essentials/Permissions/Permissions.android.cs +++ b/Xamarin.Essentials/Permissions/Permissions.android.cs @@ -29,10 +29,23 @@ public static bool IsDeclaredInManifest(string permission) internal static void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) => BasePlatformPermission.OnRequestPermissionsResult(requestCode, permissions, grantResults); + public partial class PermissionResult + { + public PermissionResult(string[] permissions, Permission[] grantResults) + { + Permissions = permissions; + GrantResults = grantResults; + } + + public string[] Permissions { get; } + + public Permission[] GrantResults { get; } + } + public abstract partial class BasePlatformPermission : BasePermission { - static readonly Dictionary tcs)> requests = - new Dictionary)>(); + static readonly Dictionary> requests = + new Dictionary>(); static readonly object locker = new object(); static int requestCode; @@ -79,9 +92,6 @@ public override async Task RequestAsync() if (await CheckStatusAsync() == PermissionStatus.Granted) return PermissionStatus.Granted; - TaskCompletionSource tcs; - var doRequest = true; - var runtimePermissions = RequiredPermissions.Where(p => p.isRuntime) ?.Select(p => p.androidPermission)?.ToArray(); @@ -90,38 +100,32 @@ public override async Task RequestAsync() if (runtimePermissions == null || !runtimePermissions.Any()) return PermissionStatus.Granted; - var permissionId = string.Join(';', runtimePermissions); + var permissionResult = await DoRequest(runtimePermissions); + if (permissionResult.GrantResults.Any(g => g == Permission.Denied)) + return PermissionStatus.Denied; + + return PermissionStatus.Granted; + } + + protected virtual async Task DoRequest(string[] permissions) + { + TaskCompletionSource tcs; lock (locker) { - if (requests.ContainsKey(permissionId)) - { - tcs = requests[permissionId].tcs; - doRequest = false; - } - else - { - tcs = new TaskCompletionSource(); + tcs = new TaskCompletionSource(); - requestCode = Platform.NextRequestCode(); + requestCode = Platform.NextRequestCode(); - requests.Add(permissionId, (requestCode, tcs)); - } + requests.Add(requestCode, tcs); } - if (!doRequest) - return await tcs.Task; - if (!MainThread.IsMainThread) throw new PermissionException("Permission request must be invoked on main thread."); - ActivityCompat.RequestPermissions(Platform.GetCurrentActivity(true), runtimePermissions.ToArray(), requestCode); + ActivityCompat.RequestPermissions(Platform.GetCurrentActivity(true), permissions.ToArray(), requestCode); var result = await tcs.Task; - - if (requests.ContainsKey(permissionId)) - requests.Remove(permissionId); - return result; } @@ -157,22 +161,11 @@ internal static void OnRequestPermissionsResult(int requestCode, string[] permis { lock (locker) { - // Check our pending requests for one with a matching request code - foreach (var kvp in requests) + if (requests.ContainsKey(requestCode)) { - if (kvp.Value.requestCode == requestCode) - { - var tcs = kvp.Value.tcs; - - // Look for any denied requests, and deny the whole request if so - // Remember, each PermissionType is tied to 1 or more android permissions - // so if any android permissions denied the whole PermissionType is considered denied - if (grantResults.Any(g => g == Permission.Denied)) - tcs.TrySetResult(PermissionStatus.Denied); - else - tcs.TrySetResult(PermissionStatus.Granted); - break; - } + var result = new PermissionResult(permissions, grantResults); + requests[requestCode].TrySetResult(result); + requests.Remove(requestCode); } } } @@ -239,6 +232,24 @@ public override (string androidPermission, bool isRuntime)[] RequiredPermissions (Manifest.Permission.AccessCoarseLocation, true), (Manifest.Permission.AccessFineLocation, true) }; + + public override async Task RequestAsync() + { + // Check status before requesting first + if (await CheckStatusAsync() == PermissionStatus.Granted) + return PermissionStatus.Granted; + + var permissionResult = await DoRequest(new string[] { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation }); + + // when requesting fine location, user can decline and set coarse instead + var count = permissionResult.GrantResults.Count(x => x == Permission.Granted); + return count switch + { + 2 => PermissionStatus.Granted, + 1 => PermissionStatus.Restricted, + _ => PermissionStatus.Denied + }; + } } public partial class LocationAlways : BasePlatformPermission @@ -260,6 +271,26 @@ public override (string androidPermission, bool isRuntime)[] RequiredPermissions return permissions.ToArray(); } } + + + public override async Task RequestAsync() + { + // Check status before requesting first + if (await CheckStatusAsync() == PermissionStatus.Granted) + return PermissionStatus.Granted; + + if (Platform.HasApiLevel(BuildVersionCodes.R)) + var permissionResult = await DoRequest(new string[] { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation }); + + // when requesting fine location, user can decline and set coarse instead + var count = permissionResult.GrantResults.Count(x => x == Permission.Granted); + var result = count switch + { + 2 => PermissionStatus.Granted, + 1 => PermissionStatus.Restricted, + _ => PermissionStatus.Denied + }; + } } public partial class Maps : BasePlatformPermission From 81832e532ba0dacd1a5e2b926836e3186a22c1b6 Mon Sep 17 00:00:00 2001 From: Allan Ritchie Date: Mon, 6 Dec 2021 21:50:56 -0500 Subject: [PATCH 06/11] Should not have been added 1912 --- .../Permissions/Permissions.android.cs | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/Xamarin.Essentials/Permissions/Permissions.android.cs b/Xamarin.Essentials/Permissions/Permissions.android.cs index 3fb5029cb..29793f80b 100644 --- a/Xamarin.Essentials/Permissions/Permissions.android.cs +++ b/Xamarin.Essentials/Permissions/Permissions.android.cs @@ -271,26 +271,6 @@ public override (string androidPermission, bool isRuntime)[] RequiredPermissions return permissions.ToArray(); } } - - - public override async Task RequestAsync() - { - // Check status before requesting first - if (await CheckStatusAsync() == PermissionStatus.Granted) - return PermissionStatus.Granted; - - if (Platform.HasApiLevel(BuildVersionCodes.R)) - var permissionResult = await DoRequest(new string[] { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation }); - - // when requesting fine location, user can decline and set coarse instead - var count = permissionResult.GrantResults.Count(x => x == Permission.Granted); - var result = count switch - { - 2 => PermissionStatus.Granted, - 1 => PermissionStatus.Restricted, - _ => PermissionStatus.Denied - }; - } } public partial class Maps : BasePlatformPermission From 414ce94041501eb438c6091d7205b7f2306f0438 Mon Sep 17 00:00:00 2001 From: Allan Ritchie Date: Mon, 6 Dec 2021 22:32:11 -0500 Subject: [PATCH 07/11] Fix #1936 - move bg permission to separate request on api30+ --- .../Permissions/Permissions.android.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Xamarin.Essentials/Permissions/Permissions.android.cs b/Xamarin.Essentials/Permissions/Permissions.android.cs index 29793f80b..e80105ae7 100644 --- a/Xamarin.Essentials/Permissions/Permissions.android.cs +++ b/Xamarin.Essentials/Permissions/Permissions.android.cs @@ -271,6 +271,30 @@ public override (string androidPermission, bool isRuntime)[] RequiredPermissions return permissions.ToArray(); } } + +#if __ANDROID_29__ + public override async Task RequestAsync() + { + // Check status before requesting first + if (await CheckStatusAsync() == PermissionStatus.Granted) + return PermissionStatus.Granted; + + if (Platform.HasApiLevel(30)) + { + var permissionResult = await new LocationWhenInUse().RequestAsync(); + if (permissionResult == PermissionStatus.Denied) + return PermissionStatus.Denied; + + var result = await DoRequest(new string[] { Manifest.Permission.AccessBackgroundLocation }); + if (!result.GrantResults.All(x => x == Permission.Granted)) + permissionResult = PermissionStatus.Restricted; + + return permissionResult; + } + + return await base.RequestAsync(); + } +#endif } public partial class Maps : BasePlatformPermission From 2d92ccd50ca2c05ec47beb6527f444ecbc69ccd5 Mon Sep 17 00:00:00 2001 From: James Montemagno Date: Wed, 5 Jan 2022 15:19:04 -0800 Subject: [PATCH 08/11] Update feature-request.md (#1898) --- .github/ISSUE_TEMPLATE/feature-request.md | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index e741c1570..d8dc9b817 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -6,22 +6,4 @@ labels: feature-request assignees: '' --- - -## Summary -Please provide a brief summary of your proposal. Two to three sentences is best here. - -## API Changes - -Include a list of all API changes, additions, subtractions as would be required by your proposal. These APIs should be considered placeholders, so the naming is not as important as getting the concepts correct. If possible you should include some "example" code of usage of your new API. You should also provide details of the level of availability for the feature on each of the supported platforms. - -e.g. - -In order to facilitate the new Shiny Button api, a bool is added to the Button class. This is done as a bool because it is simpler to data bind and other reasons... - - var button = new Button (); - button.MakeShiny = true; // new API - -The MakeShiny API works even if the button is already visible. - -## Intended Use Case -Provide a detailed example of where your proposal would be used and for what purpose. \ No newline at end of file +We are no longer accepting new feature request for Xamarin.Essentials. Please make your new feature requests in the .NET MAUI repo which contains .NET MAUI Essentials. From 85271e42c2b9e118a66224242f847d9298f15fda Mon Sep 17 00:00:00 2001 From: Gerald Versluis Date: Mon, 10 Jan 2022 22:03:01 +0100 Subject: [PATCH 09/11] CI fixes (#1946) * Updates across the board * Update Sample.Server.WebAuthenticator.csproj * Update azure-pipelines.yml * Revert "Update azure-pipelines.yml" This reverts commit 57ebfdf3d62ac54ce476e8e8650fd2d6ba637433. * Update Sample.Server.WebAuthenticator.csproj * iOS env var instead of launch arg * Update azure-pipelines.yml * Change Android target * Update DeviceTests.Android.csproj * Update azure-pipelines.yml --- .../DeviceTests.Android.csproj | 6 ++-- .../Properties/AndroidManifest.xml | 31 +++++++++++++++++ .../DeviceTests.iOS/DeviceTests.iOS.csproj | 2 +- DeviceTests/DeviceTests.iOS/Main.cs | 9 ++--- DeviceTests/build.cake | 5 +-- .../Sample.Server.WebAuthenticator.csproj | 14 ++++---- Samples/Samples.iOS/Main.cs | 2 +- azure-pipelines.yml | 34 +++++++++---------- devopsnuget.config | 1 + 9 files changed, 68 insertions(+), 36 deletions(-) diff --git a/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj b/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj index bb5e8ff69..ec88c04ec 100644 --- a/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj +++ b/DeviceTests/DeviceTests.Android/DeviceTests.Android.csproj @@ -9,7 +9,6 @@ DeviceTests.Droid XamarinEssentialsDeviceTestsAndroid v10.0 - false True true Resource @@ -19,6 +18,7 @@ true true Xamarin.Android.Net.AndroidClientHandler + armeabi-v7a;x86;x86_64;arm64-v8a true @@ -29,7 +29,6 @@ prompt 4 None - armeabi-v7a;x86;x86_64;arm64-v8a 1G false false @@ -47,7 +46,6 @@ 4 true false - armeabi-v7a;x86;x86_64;arm64-v8a true 1G @@ -63,7 +61,7 @@ - + diff --git a/DeviceTests/DeviceTests.Android/Properties/AndroidManifest.xml b/DeviceTests/DeviceTests.Android/Properties/AndroidManifest.xml index 4ab740cad..7d1546089 100644 --- a/DeviceTests/DeviceTests.Android/Properties/AndroidManifest.xml +++ b/DeviceTests/DeviceTests.Android/Properties/AndroidManifest.xml @@ -12,5 +12,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DeviceTests/DeviceTests.iOS/DeviceTests.iOS.csproj b/DeviceTests/DeviceTests.iOS/DeviceTests.iOS.csproj index 8085b44b7..cedc68a32 100644 --- a/DeviceTests/DeviceTests.iOS/DeviceTests.iOS.csproj +++ b/DeviceTests/DeviceTests.iOS/DeviceTests.iOS.csproj @@ -80,7 +80,7 @@ - + diff --git a/DeviceTests/DeviceTests.iOS/Main.cs b/DeviceTests/DeviceTests.iOS/Main.cs index c79e23b40..82ad09057 100644 --- a/DeviceTests/DeviceTests.iOS/Main.cs +++ b/DeviceTests/DeviceTests.iOS/Main.cs @@ -1,4 +1,5 @@ -using UIKit; +using System; +using UIKit; namespace DeviceTests.iOS { @@ -6,10 +7,10 @@ public class Application { static void Main(string[] args) { - if (args?.Length > 0) // usually means this is from xharness - UIApplication.Main(args, null, nameof(TestApplicationDelegate)); + if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("ci-run"))) + UIApplication.Main(args, null, typeof(TestApplicationDelegate)); else - UIApplication.Main(args, null, nameof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/DeviceTests/build.cake b/DeviceTests/build.cake index 5f851f1f9..69aa1586b 100644 --- a/DeviceTests/build.cake +++ b/DeviceTests/build.cake @@ -118,11 +118,12 @@ Task("test-ios-emu") CleanDirectories(IOS_TEST_RESULTS_PATH.FullPath); // Run the tests - var resultCode = StartProcess("xharness", "ios test " + + var resultCode = StartProcess("xharness", "apple test " + $"--app=\"{IOS_IPA_PATH}\" " + $"--targets=\"ios-simulator-64\" " + $"--output-directory=\"{IOS_TEST_RESULTS_PATH}\" " + - $"--verbosity=\"Debug\" "); + $"--verbosity=\"Debug\" " + + $"--set-env=ci-run=true "); // Rename test result files var resultFiles = GetFiles($"{IOS_TEST_RESULTS_PATH}/*.xml"); diff --git a/Samples/Sample.Server.WebAuthenticator/Sample.Server.WebAuthenticator.csproj b/Samples/Sample.Server.WebAuthenticator/Sample.Server.WebAuthenticator.csproj index 511006200..1615b2910 100644 --- a/Samples/Sample.Server.WebAuthenticator/Sample.Server.WebAuthenticator.csproj +++ b/Samples/Sample.Server.WebAuthenticator/Sample.Server.WebAuthenticator.csproj @@ -1,16 +1,16 @@ - net5.0 + netcoreapp3.1 - - - - - - + + + + + + diff --git a/Samples/Samples.iOS/Main.cs b/Samples/Samples.iOS/Main.cs index 0bb5eadad..5ece82925 100644 --- a/Samples/Samples.iOS/Main.cs +++ b/Samples/Samples.iOS/Main.cs @@ -6,7 +6,7 @@ public class Application { static void Main(string[] args) { - UIApplication.Main(args, null, nameof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index ee4b63af1..d8b126a75 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,7 +8,7 @@ pr: - develop variables: - BASE_VERSION: 1.6.2 + BASE_VERSION: 1.7.1 PREVIEW_LABEL: 'ci' BUILD_NUMBER: $[counter(format('{0}_{1}_{2}', variables['BASE_VERSION'], variables['PREVIEW_LABEL'], variables['Build.SourceBranch']), 1)] NUGET_VERSION: $[format('{0}-{1}.{2}', variables['BASE_VERSION'], variables['PREVIEW_LABEL'], variables['BUILD_NUMBER'])] @@ -99,7 +99,7 @@ stages: verbosity: diagnostic cakeFile: DeviceTests/build.cake cakeTarget: test-ios-emu - cakeExtraArgs: --ios-device="`"iPhone 11`"" --ios-runtime="`"com.apple.CoreSimulator.SimRuntime.iOS-14-2`"" + xharness: '1.0.0-prerelease.21620.1' - template: .ci/build.yml@components parameters: @@ -198,18 +198,18 @@ stages: - bash: sh -c "echo \"y\" | $ANDROID_HOME/tools/bin/sdkmanager \"system-images;android-29;google_apis;x86\"" displayName: Install the Android emulators - - template: .ci/build.yml@components - parameters: - name: devicetests_android_api_30 - runChecks: false - displayName: Android API 30 - publishOutputSuffix: '-android30' - windowsImage: '' - areaPath: $(AREA_PATH) - verbosity: diagnostic - cakeFile: DeviceTests/build.cake - cakeTarget: test-android-emu - cakeExtraArgs: --avd-target="`"system-images;android-30;google_apis;x86`"" - preBuildSteps: - - bash: sh -c "echo \"y\" | $ANDROID_HOME/tools/bin/sdkmanager \"system-images;android-30;google_apis;x86\"" - displayName: Install the Android emulators + # - template: .ci/build.yml@components + # parameters: + # name: devicetests_android_api_30 + # runChecks: false + # displayName: Android API 30 + # publishOutputSuffix: '-android30' + # windowsImage: '' + # areaPath: $(AREA_PATH) + # verbosity: diagnostic + # cakeFile: DeviceTests/build.cake + # cakeTarget: test-android-emu + # cakeExtraArgs: --avd-target="`"system-images;android-30;google_apis;x86`"" + # preBuildSteps: + # - bash: sh -c "echo \"y\" | $ANDROID_HOME/tools/bin/sdkmanager \"system-images;android-30;google_apis;x86\"" + # displayName: Install the Android emulators diff --git a/devopsnuget.config b/devopsnuget.config index db87568b5..8f831e620 100644 --- a/devopsnuget.config +++ b/devopsnuget.config @@ -4,6 +4,7 @@ + From afae843e870a3b1357ae9aba4a19df1bade14bda Mon Sep 17 00:00:00 2001 From: Jonathan Dick Date: Wed, 12 Jan 2022 13:04:11 -0500 Subject: [PATCH 10/11] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c5a3e24f6..c0dc98d5a 100644 --- a/README.md +++ b/README.md @@ -77,3 +77,5 @@ Here are some frequently asked questions about Xamarin.Essentials, but be sure t Please see the [License](LICENSE). +## Stats + From b9ad98bcffc171f32c5334d3fe96d68c5fb2c2fc Mon Sep 17 00:00:00 2001 From: Dima Dimov Date: Thu, 13 Jan 2022 03:06:57 +0300 Subject: [PATCH 11/11] Improving the operation of PresentationControllers (#1846) Co-authored-by: Matthew Leibowitz --- .../Contacts/Contacts.ios.macos.cs | 8 +++++ Xamarin.Essentials/Email/Email.ios.cs | 13 +++++++-- .../FilePicker/FilePicker.ios.cs | 12 ++------ .../MediaPicker/MediaPicker.ios.cs | 12 ++------ .../Platform/Platform.ios.tvos.watchos.cs | 29 ++++++++++++++++++- Xamarin.Essentials/Sms/Sms.ios.cs | 10 ++++++- 6 files changed, 60 insertions(+), 24 deletions(-) diff --git a/Xamarin.Essentials/Contacts/Contacts.ios.macos.cs b/Xamarin.Essentials/Contacts/Contacts.ios.macos.cs index d1b54132e..17022bb04 100644 --- a/Xamarin.Essentials/Contacts/Contacts.ios.macos.cs +++ b/Xamarin.Essentials/Contacts/Contacts.ios.macos.cs @@ -39,6 +39,14 @@ static Task PlatformPickContactAsync() }) }; + if (picker.PresentationController != null) + { + picker.PresentationController.Delegate = new Platform.UIPresentationControllerDelegate + { + DismissHandler = () => source?.TrySetResult(null) + }; + } + uiView.PresentViewController(picker, true, null); return source.Task; diff --git a/Xamarin.Essentials/Email/Email.ios.cs b/Xamarin.Essentials/Email/Email.ios.cs index 0415350cb..5b0cf6613 100644 --- a/Xamarin.Essentials/Email/Email.ios.cs +++ b/Xamarin.Essentials/Email/Email.ios.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Threading.Tasks; using Foundation; using MessageUI; @@ -50,13 +51,21 @@ static Task ComposeWithMailCompose(EmailMessage message) } } - // show the controller var tcs = new TaskCompletionSource(); controller.Finished += (sender, e) => { controller.DismissViewController(true, null); tcs.TrySetResult(e.Result == MFMailComposeResult.Sent); }; + + if (controller.PresentationController != null) + { + controller.PresentationController.Delegate = new Platform.UIPresentationControllerDelegate + { + DismissHandler = () => tcs.TrySetResult(false) + }; + } + parentController.PresentViewController(controller, true, null); return tcs.Task; diff --git a/Xamarin.Essentials/FilePicker/FilePicker.ios.cs b/Xamarin.Essentials/FilePicker/FilePicker.ios.cs index 284829ddc..76516c429 100644 --- a/Xamarin.Essentials/FilePicker/FilePicker.ios.cs +++ b/Xamarin.Essentials/FilePicker/FilePicker.ios.cs @@ -34,9 +34,9 @@ static async Task> PlatformPickAsync(PickOptions options if (documentPicker.PresentationController != null) { - documentPicker.PresentationController.Delegate = new PickerPresentationControllerDelegate + documentPicker.PresentationController.Delegate = new Platform.UIPresentationControllerDelegate { - PickHandler = urls => GetFileResults(urls, tcs) + DismissHandler = () => GetFileResults(null, tcs) }; } @@ -74,14 +74,6 @@ public override void DidPickDocument(UIDocumentPickerViewController controller, public override void DidPickDocument(UIDocumentPickerViewController controller, NSUrl url) => PickHandler?.Invoke(new NSUrl[] { url }); } - - class PickerPresentationControllerDelegate : UIAdaptivePresentationControllerDelegate - { - public Action PickHandler { get; set; } - - public override void DidDismiss(UIPresentationController presentationController) => - PickHandler?.Invoke(null); - } } public partial class FilePickerFileType diff --git a/Xamarin.Essentials/MediaPicker/MediaPicker.ios.cs b/Xamarin.Essentials/MediaPicker/MediaPicker.ios.cs index 6c38e5682..44a06155a 100644 --- a/Xamarin.Essentials/MediaPicker/MediaPicker.ios.cs +++ b/Xamarin.Essentials/MediaPicker/MediaPicker.ios.cs @@ -75,9 +75,9 @@ static async Task PhotoAsync(MediaPickerOptions options, bool photo, if (picker.PresentationController != null) { - picker.PresentationController.Delegate = new PhotoPickerPresentationControllerDelegate + picker.PresentationController.Delegate = new Platform.UIPresentationControllerDelegate { - CompletedHandler = info => GetFileResult(info, tcs) + DismissHandler = () => GetFileResult(null, tcs) }; } @@ -167,13 +167,5 @@ public override void FinishedPickingMedia(UIImagePickerController picker, NSDict public override void Canceled(UIImagePickerController picker) => CompletedHandler?.Invoke(null); } - - class PhotoPickerPresentationControllerDelegate : UIAdaptivePresentationControllerDelegate - { - public Action CompletedHandler { get; set; } - - public override void DidDismiss(UIPresentationController presentationController) => - CompletedHandler?.Invoke(null); - } } } diff --git a/Xamarin.Essentials/Platform/Platform.ios.tvos.watchos.cs b/Xamarin.Essentials/Platform/Platform.ios.tvos.watchos.cs index 635e4d3f7..3461d6e6d 100644 --- a/Xamarin.Essentials/Platform/Platform.ios.tvos.watchos.cs +++ b/Xamarin.Essentials/Platform/Platform.ios.tvos.watchos.cs @@ -73,12 +73,20 @@ internal static bool HasOSVersion(int major, int minor) => #if __IOS__ || __TVOS__ + static Func getCurrentController; + + public static void Init(Func getCurrentUIViewController) + => getCurrentController = getCurrentUIViewController; + public static UIViewController GetCurrentUIViewController() => GetCurrentViewController(false); internal static UIViewController GetCurrentViewController(bool throwIfNull = true) { - UIViewController viewController = null; + var viewController = getCurrentController?.Invoke(); + + if (viewController != null) + return viewController; var window = UIApplication.SharedApplication.KeyWindow; @@ -138,5 +146,24 @@ internal static UIWindow GetCurrentWindow(bool throwIfNull = true) internal static NSOperationQueue GetCurrentQueue() => NSOperationQueue.CurrentQueue ?? new NSOperationQueue(); + +#if __IOS__ + internal class UIPresentationControllerDelegate : UIAdaptivePresentationControllerDelegate + { + public Action DismissHandler { get; set; } + + public override void DidDismiss(UIPresentationController presentationController) + { + DismissHandler?.Invoke(); + DismissHandler = null; + } + + protected override void Dispose(bool disposing) + { + DismissHandler?.Invoke(); + base.Dispose(disposing); + } + } +#endif } } diff --git a/Xamarin.Essentials/Sms/Sms.ios.cs b/Xamarin.Essentials/Sms/Sms.ios.cs index 19da4bbb1..acd775f99 100644 --- a/Xamarin.Essentials/Sms/Sms.ios.cs +++ b/Xamarin.Essentials/Sms/Sms.ios.cs @@ -21,13 +21,21 @@ static Task PlatformComposeAsync(SmsMessage message) messageController.Recipients = message?.Recipients?.ToArray() ?? new string[] { }; - // show the controller var tcs = new TaskCompletionSource(); messageController.Finished += (sender, e) => { messageController.DismissViewController(true, null); tcs?.TrySetResult(e.Result == MessageComposeResult.Sent); }; + + if (controller.PresentationController != null) + { + controller.PresentationController.Delegate = new Platform.UIPresentationControllerDelegate + { + DismissHandler = () => tcs.TrySetResult(false) + }; + } + controller.PresentViewController(messageController, true, null); return tcs.Task;