Skip to content

Commit 85af246

Browse files
committed
Merge branch 'develop' into 1.6.0
2 parents f30a865 + 94717ca commit 85af246

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+586
-73
lines changed

Diff for: CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Every pull request which affects public types or members should include correspo
8787

8888
If you're looking for something to fix, please browse [open issues](https://github.com/xamarin/Essentials/issues).
8989

90-
Follow the style used by the [.NET Foundation](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md), with two primary exceptions:
90+
Follow the style used by the [.NET Foundation](https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md), with two primary exceptions:
9191

9292
- We do not use the `private` keyword as it is the default accessibility level in C#.
9393
- We will **not** use `_` or `s_` as a prefix for internal or private field names
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using Xamarin.Essentials;
3+
using Xunit;
4+
5+
namespace DeviceTests
6+
{
7+
public class HapticFeedback_Tests
8+
{
9+
[Fact]
10+
public void Click() => HapticFeedback.Perform(HapticFeedbackType.Click);
11+
12+
[Fact]
13+
public void LongPress() => HapticFeedback.Perform(HapticFeedbackType.LongPress);
14+
}
15+
}

Diff for: Samples/Sample.Server.WebAuthenticator/Controllers/MobileAuthController.cs

+10-5
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,18 @@ public async Task Get([FromRoute]string scheme)
3131
}
3232
else
3333
{
34+
var claims = auth.Principal.Identities.FirstOrDefault()?.Claims;
35+
var email = string.Empty;
36+
email = claims?.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Email)?.Value;
37+
3438
// Get parameters to send back to the callback
3539
var qs = new Dictionary<string, string>
36-
{
37-
{ "access_token", auth.Properties.GetTokenValue("access_token") },
38-
{ "refresh_token", auth.Properties.GetTokenValue("refresh_token") ?? string.Empty },
39-
{ "expires", (auth.Properties.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToString() }
40-
};
40+
{
41+
{ "access_token", auth.Properties.GetTokenValue("access_token") },
42+
{ "refresh_token", auth.Properties.GetTokenValue("refresh_token") ?? string.Empty },
43+
{ "expires", (auth.Properties.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToString() },
44+
{ "email", email }
45+
};
4146

4247
// Build the result url
4348
var url = callbackScheme + "://#" + string.Join(

Diff for: Samples/Sample.Server.WebAuthenticator/Startup.cs

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ public void ConfigureServices(IServiceCollection services)
6262
=> WebHostEnvironment.ContentRootFileProvider.GetFileInfo($"AuthKey_{keyId}.p8"));
6363
a.SaveTokens = true;
6464
});
65+
66+
/*
67+
* For Apple signin
68+
* If you are running the app on Azure you must add the Configuration setting
69+
* WEBSITE_LOAD_USER_PROFILE = 1
70+
* Without this setting you will get a File Not Found exception when AppleAuthenticationHandler tries to generate a certificate using your Auth_{keyId].P8 file.
71+
*/
6572
}
6673

6774
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

Diff for: Samples/Samples.Android/Samples.Android.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
<AndroidManagedSymbols>true</AndroidManagedSymbols>
4545
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
4646
<AndroidSupportedAbis>armeabi-v7a;x86</AndroidSupportedAbis>
47-
<EnableProguard>true</EnableProguard>
47+
<AndroidLinkTool>r8</AndroidLinkTool>
4848
<AndroidLinkMode>Full</AndroidLinkMode>
4949
<AndroidLinkSkip>Xamarin.Forms.Platform.Android;Xamarin.Forms.Platform;Xamarin.Forms.Core;Xamarin.Forms.Xaml;Samples;FormsViewGroup;</AndroidLinkSkip>
5050
</PropertyGroup>
@@ -123,4 +123,4 @@
123123
<AndroidAsset Include="Assets\FileSystemTemplate.txt" />
124124
</ItemGroup>
125125
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
126-
</Project>
126+
</Project>

Diff for: Samples/Samples/View/HapticFeedbackPage.xaml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<views:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
3+
xmlns:views="clr-namespace:Samples.View"
4+
xmlns:viewmodels="clr-namespace:Samples.ViewModel"
5+
x:Class="Samples.View.HapticFeedbackPage"
6+
Title="Vibration">
7+
<views:BasePage.BindingContext>
8+
<viewmodels:HapticFeedbackViewModel />
9+
</views:BasePage.BindingContext>
10+
11+
<StackLayout>
12+
<Label Text="Quickly and easily make the device provide haptic feedback." FontAttributes="Bold" Margin="12" />
13+
14+
<ScrollView>
15+
<StackLayout Padding="12,0,12,12" Spacing="6">
16+
<Button Text="Click" Command="{Binding ClickCommand}" />
17+
<Button Text="LongPress" Command="{Binding LongPressCommand}" />
18+
<Label Text="HapticFeadback is not supported." TextColor="Red" FontAttributes="Italic"
19+
IsVisible="{Binding IsSupported, Converter={StaticResource NegativeConverter}}" />
20+
</StackLayout>
21+
</ScrollView>
22+
</StackLayout>
23+
24+
</views:BasePage>

Diff for: Samples/Samples/View/HapticFeedbackPage.xaml.cs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Samples.View
2+
{
3+
public partial class HapticFeedbackPage : BasePage
4+
{
5+
public HapticFeedbackPage()
6+
{
7+
InitializeComponent();
8+
}
9+
}
10+
}

Diff for: Samples/Samples/ViewModel/HapticFeedbackViewModel.cs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System;
2+
using System.Windows.Input;
3+
using Xamarin.Essentials;
4+
using Xamarin.Forms;
5+
6+
namespace Samples.ViewModel
7+
{
8+
public class HapticFeedbackViewModel : BaseViewModel
9+
{
10+
bool isSupported = true;
11+
12+
public HapticFeedbackViewModel()
13+
{
14+
ClickCommand = new Command(OnClick);
15+
LongPressCommand = new Command(OnLongPress);
16+
}
17+
18+
public ICommand ClickCommand { get; }
19+
20+
public ICommand LongPressCommand { get; }
21+
22+
public bool IsSupported
23+
{
24+
get => isSupported;
25+
set => SetProperty(ref isSupported, value);
26+
}
27+
28+
void OnClick()
29+
{
30+
try
31+
{
32+
HapticFeedback.Perform(HapticFeedbackType.Click);
33+
}
34+
catch (FeatureNotSupportedException)
35+
{
36+
IsSupported = false;
37+
}
38+
catch (Exception ex)
39+
{
40+
DisplayAlertAsync($"Unable to HapticFeedback: {ex.Message}");
41+
}
42+
}
43+
44+
void OnLongPress()
45+
{
46+
try
47+
{
48+
HapticFeedback.Perform(HapticFeedbackType.LongPress);
49+
}
50+
catch (FeatureNotSupportedException)
51+
{
52+
IsSupported = false;
53+
}
54+
catch (Exception ex)
55+
{
56+
DisplayAlertAsync($"Unable to HapticFeedback: {ex.Message}");
57+
}
58+
}
59+
}
60+
}

Diff for: Samples/Samples/ViewModel/HomeViewModel.cs

+6
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@ public HomeViewModel()
204204
typeof(VibrationPage),
205205
"Quickly and easily make the device vibrate.",
206206
new[] { "vibration", "vibrate", "hardware", "device" }),
207+
new SampleItem(
208+
"📳",
209+
"Haptic Feedback",
210+
typeof(HapticFeedbackPage),
211+
"Quickly and easily make the device provide haptic feedback",
212+
new[] { "haptic", "feedback", "hardware", "device" }),
207213
new SampleItem(
208214
"🔓",
209215
"Web Authenticator",

Diff for: Xamarin.Essentials.sln

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{6330
2929
EndProject
3030
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{EE4495FA-9869-45CF-A11D-69F2218C6F62}"
3131
EndProject
32-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Server.WebAuthenticator", "Samples\Sample.Server.WebAuthenticator\Sample.Server.WebAuthenticator.csproj", "{553D51A8-8E79-40D9-9FB3-9FC2386FF886}"
32+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Server.WebAuthenticator", "Samples\Sample.Server.WebAuthenticator\Sample.Server.WebAuthenticator.csproj", "{553D51A8-8E79-40D9-9FB3-9FC2386FF886}"
3333
EndProject
3434
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.Mac", "Samples\Samples.Mac\Samples.Mac.csproj", "{89899D16-4BD1-49B1-9903-9F6BB26C5DC5}"
3535
EndProject

Diff for: Xamarin.Essentials/Email/Email.android.cs

+11-3
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,18 @@ static Task PlatformComposeAsync(EmailMessage message)
3434

3535
static Intent CreateIntent(EmailMessage message)
3636
{
37-
var action = message?.Attachments?.Count > 1 ? Intent.ActionSendMultiple : Intent.ActionSend;
37+
var action = (message?.Attachments?.Count ?? 0) switch
38+
{
39+
0 => Intent.ActionSendto,
40+
1 => Intent.ActionSend,
41+
_ => Intent.ActionSendMultiple
42+
};
3843
var intent = new Intent(action);
39-
intent.SetType("message/rfc822");
40-
intent.SetData(Uri.Parse("mailto:")); // only email apps should handle this
44+
45+
if (action == Intent.ActionSendto)
46+
intent.SetData(Uri.Parse("mailto:"));
47+
else
48+
intent.SetType("message/rfc822");
4149

4250
if (!string.IsNullOrEmpty(message?.Body))
4351
{

Diff for: Xamarin.Essentials/Flashlight/Flashlight.android.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static async Task CheckSupportAsync()
4141
if (!IsSupported)
4242
throw new FeatureNotSupportedException();
4343

44-
await Permissions.RequestAsync<Permissions.Flashlight>();
44+
await Permissions.EnsureGrantedAsync<Permissions.Flashlight>();
4545
}
4646

4747
static Task ToggleTorchAsync(bool switchOn)

Diff for: Xamarin.Essentials/Geolocation/Geolocation.android.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static partial class Geolocation
1919

2020
static async Task<Location> PlatformLastKnownLocationAsync()
2121
{
22-
await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
22+
await Permissions.EnsureGrantedAsync<Permissions.LocationWhenInUse>();
2323

2424
var lm = Platform.LocationManager;
2525
AndroidLocation bestLocation = null;
@@ -37,7 +37,7 @@ static async Task<Location> PlatformLastKnownLocationAsync()
3737

3838
static async Task<Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
3939
{
40-
await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
40+
await Permissions.EnsureGrantedAsync<Permissions.LocationWhenInUse>();
4141

4242
var locationManager = Platform.LocationManager;
4343

Diff for: Xamarin.Essentials/Geolocation/Geolocation.ios.macos.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ static async Task<Location> PlatformLastKnownLocationAsync()
1414
if (!CLLocationManager.LocationServicesEnabled)
1515
throw new FeatureNotEnabledException("Location services are not enabled on device.");
1616

17-
await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
17+
await Permissions.EnsureGrantedAsync<Permissions.LocationWhenInUse>();
1818

1919
var manager = new CLLocationManager();
2020
var location = manager.Location;
@@ -27,7 +27,7 @@ static async Task<Location> PlatformLocationAsync(GeolocationRequest request, Ca
2727
if (!CLLocationManager.LocationServicesEnabled)
2828
throw new FeatureNotEnabledException("Location services are not enabled on device.");
2929

30-
await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
30+
await Permissions.EnsureGrantedAsync<Permissions.LocationWhenInUse>();
3131

3232
// the location manager requires an active run loop
3333
// so just use the main loop

Diff for: Xamarin.Essentials/Geolocation/Geolocation.tizen.cs

+2-7
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,11 @@ public static partial class Geolocation
88
{
99
static Location lastKnownLocation = new Location();
1010

11-
static async Task<Location> PlatformLastKnownLocationAsync()
12-
{
13-
await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
14-
15-
return lastKnownLocation;
16-
}
11+
static Task<Location> PlatformLastKnownLocationAsync() => Task.FromResult(lastKnownLocation);
1712

1813
static async Task<Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
1914
{
20-
await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
15+
await Permissions.EnsureGrantedAsync<Permissions.LocationWhenInUse>();
2116

2217
Locator service = null;
2318
var gps = Platform.GetFeatureInfo<bool>("location.gps");

Diff for: Xamarin.Essentials/Geolocation/Geolocation.uwp.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ static async Task<Location> PlatformLastKnownLocationAsync()
2525

2626
static async Task<Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
2727
{
28-
await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
28+
await Permissions.EnsureGrantedAsync<Permissions.LocationWhenInUse>();
2929

3030
var geolocator = new Geolocator
3131
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Threading.Tasks;
4+
using Android.Views;
5+
6+
namespace Xamarin.Essentials
7+
{
8+
public static partial class HapticFeedback
9+
{
10+
internal static bool IsSupported => true;
11+
12+
static void PlatformPerform(HapticFeedbackType type)
13+
{
14+
Permissions.EnsureDeclared<Permissions.Vibrate>();
15+
16+
try
17+
{
18+
Platform.CurrentActivity?.Window?.DecorView?.PerformHapticFeedback(ConvertType(type));
19+
}
20+
catch (Exception ex)
21+
{
22+
Debug.WriteLine($"HapticFeedback Exception: {ex.Message}");
23+
}
24+
}
25+
26+
static FeedbackConstants ConvertType(HapticFeedbackType type) =>
27+
type switch
28+
{
29+
HapticFeedbackType.LongPress => FeedbackConstants.LongPress,
30+
_ => FeedbackConstants.ContextClick
31+
};
32+
}
33+
}
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using UIKit;
4+
5+
namespace Xamarin.Essentials
6+
{
7+
public static partial class HapticFeedback
8+
{
9+
internal static bool IsSupported => true;
10+
11+
static void PlatformPerform(HapticFeedbackType type)
12+
{
13+
switch (type)
14+
{
15+
case HapticFeedbackType.LongPress:
16+
PlatformLongPress();
17+
break;
18+
default:
19+
PlatformClick();
20+
break;
21+
}
22+
}
23+
24+
static void PlatformClick()
25+
{
26+
if (Platform.HasOSVersion(10, 0))
27+
{
28+
var impact = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Light);
29+
impact.Prepare();
30+
impact.ImpactOccurred();
31+
impact.Dispose();
32+
}
33+
}
34+
35+
static void PlatformLongPress()
36+
{
37+
if (Platform.HasOSVersion(10, 0))
38+
{
39+
var impact = new UIImpactFeedbackGenerator(UIImpactFeedbackStyle.Medium);
40+
impact.Prepare();
41+
impact.ImpactOccurred();
42+
impact.Dispose();
43+
}
44+
}
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
4+
namespace Xamarin.Essentials
5+
{
6+
public static partial class HapticFeedback
7+
{
8+
internal static bool IsSupported
9+
=> throw ExceptionUtils.NotSupportedOrImplementedException;
10+
11+
static void PlatformPerform(HapticFeedbackType type)
12+
=> throw ExceptionUtils.NotSupportedOrImplementedException;
13+
}
14+
}

0 commit comments

Comments
 (0)