diff --git a/.vsts-ci.yml b/.vsts-ci.yml index 172c90599f06..de771fbba25d 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -36,6 +36,9 @@ jobs: # Required for the Wasm uitests project - task: NodeTool@0 + - powershell: .\build\Install-WindowsSdkISO.ps1 17763 + displayName: Insider SDK + - task: MSBuild@1 inputs: solution: Build/Uno.UI.Build.csproj diff --git a/build/Install-WindowsSdkISO.ps1 b/build/Install-WindowsSdkISO.ps1 new file mode 100644 index 000000000000..5ac8ec0be807 --- /dev/null +++ b/build/Install-WindowsSdkISO.ps1 @@ -0,0 +1,302 @@ +[CmdletBinding()] +param([Parameter(Mandatory=$true)] + [string]$buildNumber) + +# Ensure the error action preference is set to the default for PowerShell3, 'Stop' +$ErrorActionPreference = 'Stop' + +# Constants +$WindowsSDKOptions = @("OptionId.UWPCpp") +$WindowsSDKRegPath = "HKLM:\Software\Microsoft\Windows Kits\Installed Roots" +$WindowsSDKRegRootKey = "KitsRoot10" +$WindowsSDKVersion = "10.0.$buildNumber.0" +$WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed Options" +$StrongNameRegPath = "HKLM:\SOFTWARE\Microsoft\StrongName\Verification" +$PublicKeyTokens = @("31bf3856ad364e35") + +function Download-File +{ + param ([string] $outDir, + [string] $downloadUrl, + [string] $downloadName) + + $downloadPath = Join-Path $outDir "$downloadName.download" + $downloadDest = Join-Path $outDir $downloadName + $downloadDestTemp = Join-Path $outDir "$downloadName.tmp" + + Write-Host -NoNewline "Downloading $downloadName..." + + try + { + $webclient = new-object System.Net.WebClient + $webclient.DownloadFile($downloadUrl, $downloadPath) + } + catch [System.Net.WebException] + { + Write-Host + Write-Warning "Failed to fetch updated file from $downloadUrl" + if (!(Test-Path $downloadDest)) + { + throw "$downloadName was not found at $downloadDest" + } + else + { + Write-Warning "$downloadName may be out of date" + } + } + + Unblock-File $downloadPath + + $downloadDestTemp = $downloadPath; + + # Delete and rename to final dest + if (Test-Path -PathType Container $downloadDest) + { + [System.IO.Directory]::Delete($downloadDest, $true) + } + + Move-Item -Force $downloadDestTemp $downloadDest + Write-Host "Done" + + return $downloadDest +} + +function Get-ISODriveLetter +{ + param ([string] $isoPath) + + $diskImage = Get-DiskImage -ImagePath $isoPath + if ($diskImage) + { + $volume = Get-Volume -DiskImage $diskImage + + if ($volume) + { + $driveLetter = $volume.DriveLetter + if ($driveLetter) + { + $driveLetter += ":" + return $driveLetter + } + } + } + + return $null +} + +function Mount-ISO +{ + param ([string] $isoPath) + + # Check if image is already mounted + $isoDrive = Get-ISODriveLetter $isoPath + + if (!$isoDrive) + { + Mount-DiskImage -ImagePath $isoPath -StorageType ISO | Out-Null + } + + $isoDrive = Get-ISODriveLetter $isoPath + Write-Verbose "$isoPath mounted to ${isoDrive}:" +} + +function Dismount-ISO +{ + param ([string] $isoPath) + + $isoDrive = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter + + if ($isoDrive) + { + Write-Verbose "$isoPath dismounted" + Dismount-DiskImage -ImagePath $isoPath | Out-Null + } +} + +function Disable-StrongName +{ + param ([string] $publicKeyToken = "*") + + reg ADD "HKLM\SOFTWARE\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null + if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") + { + reg ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null + } +} + +function Test-Admin +{ + $identity = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal $identity + $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +function Test-RegistryPathAndValue +{ + param ( + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $path, + [parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] $value) + + try + { + if (Test-Path $path) + { + Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null + return $true + } + } + catch + { + } + + return $false +} + +function Test-InstallWindowsSDK +{ + $retval = $true + + if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey) + { + # A Windows SDK is installed + # Is an SDK of our version installed with the options we need? + if (Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value "$WindowsSDKOptions") + { + # It appears we have what we need. Double check the disk + $sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey + if ($sdkRoot) + { + if (Test-Path $sdkRoot) + { + $refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion" + if (Test-Path $refPath) + { + $umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion" + if (Test-Path $umdPath) + { + # Pretty sure we have what we need + $retval = $false + } + } + } + } + } + } + + return $retval +} + +function Test-InstallStrongNameHijack +{ + foreach($publicKeyToken in $PublicKeyTokens) + { + $key = "$StrongNameRegPath\*,$publicKeyToken" + if (!(Test-Path $key)) + { + return $true + } + } + + return $false +} + +Write-Host -NoNewline "Checking for installed Windows SDK $WindowsSDKVersion..." +$InstallWindowsSDK = Test-InstallWindowsSDK +if ($InstallWindowsSDK) +{ + Write-Host "Installation required" +} +else +{ + Write-Host "INSTALLED" +} + +$StrongNameHijack = Test-InstallStrongNameHijack +Write-Host -NoNewline "Checking if StrongName bypass required..." + +if ($StrongNameHijack) +{ + Write-Host "REQUIRED" +} +else +{ + Write-Host "Done" +} + +if ($StrongNameHijack -or $InstallWindowsSDK) +{ + if (!(Test-Admin)) + { + Write-Host + throw "ERROR: Elevation required" + } +} + +if ($InstallWindowsSDK) +{ + # Static(ish) link for Windows SDK + # Note: there is a delay from Windows SDK announcements to availability via the static link + $uri = "https://go.microsoft.com/fwlink/?prd=11966&pver=1.0&plcid=0x409&clcid=0x409&ar=Flight&sar=Sdsurl&o1=$buildNumber" + + if ($env:TEMP -eq $null) + { + $env:TEMP = Join-Path $env:SystemDrive 'temp' + } + + $winsdkTempDir = Join-Path $env:TEMP "WindowsSDK" + + if (![System.IO.Directory]::Exists($winsdkTempDir)) + { + [void][System.IO.Directory]::CreateDirectory($winsdkTempDir) + } + + $file = "winsdk_$buildNumber.iso" + + Write-Verbose "Getting WinSDK from $uri" + $downloadFile = Download-File $winsdkTempDir $uri $file + + # TODO Check if zip, exe, iso, etc. + try + { + Write-Host -NoNewline "Mounting ISO $file..." + Mount-ISO $downloadFile + Write-Host "Done" + + $isoDrive = Get-ISODriveLetter $downloadFile + + if (Test-Path $isoDrive) + { + Write-Host -NoNewLine "Installing WinSDK..." + + $setupPath = Join-Path "$isoDrive" "WinSDKSetup.exe" + Start-Process -Wait $setupPath "/features $WindowsSDKOptions /q" + Write-Host "Done" + } + else + { + throw "Could not find mounted ISO at ${isoDrive}" + } + } + finally + { + Write-Host -NoNewline "Dismounting ISO $file..." + #Dismount-ISO $downloadFile + Write-Host "Done" + } +} + +if ($StrongNameHijack) +{ + Write-Host -NoNewline "Disabling StrongName for Windows SDK..." + + foreach($key in $PublicKeyTokens) + { + Disable-StrongName $key + } + + Write-Host "Done" +} \ No newline at end of file diff --git a/build/PackageDiffIgnore.xml b/build/PackageDiffIgnore.xml index 4e042bdfbe39..b5cccef6601b 100644 --- a/build/PackageDiffIgnore.xml +++ b/build/PackageDiffIgnore.xml @@ -1,6 +1,6 @@ - + - + @@ -171,11 +171,14 @@ reason="Invalid method visibility"/> - - - + + + + diff --git a/doc/ReleaseNotes/_ReleaseNotes.md b/doc/ReleaseNotes/_ReleaseNotes.md index dc28eba21918..9a76348aa6a8 100644 --- a/doc/ReleaseNotes/_ReleaseNotes.md +++ b/doc/ReleaseNotes/_ReleaseNotes.md @@ -1,6 +1,7 @@ # Release notes ## Next version +* Add support for `Windows.Phone.Devices.Notification.VibrationDevice` API on iOS, Android and WASM * `LinearGradientBrush.EndPoint` now defaults to (1,1) to match UWP * Add support for `Windows.System.Display.DisplayRequest` API on iOS and Android * Add support for the following `Windows.System.Power.PowerManager` APIs on iOS and Android: diff --git a/doc/articles/features/windows-phone-devices-notification-vibrationdevice.md b/doc/articles/features/windows-phone-devices-notification-vibrationdevice.md new file mode 100644 index 000000000000..f9570c6e5758 --- /dev/null +++ b/doc/articles/features/windows-phone-devices-notification-vibrationdevice.md @@ -0,0 +1,9 @@ +# Uno Support for Windows.Phone.Devices.Notification APIs + +## `VibrationDevice` + +### Limitations + +**iOS** +- The `Cancel` method is not supported. +- The parameter of the `Vibrate(TimeSpan)` method is not taken into account - iOS supports only a default vibration duration. \ No newline at end of file diff --git a/src/SamplesApp/SamplesApp.Droid/Properties/AndroidManifest.xml b/src/SamplesApp/SamplesApp.Droid/Properties/AndroidManifest.xml index ca45f09df613..4ef6137283d4 100644 --- a/src/SamplesApp/SamplesApp.Droid/Properties/AndroidManifest.xml +++ b/src/SamplesApp/SamplesApp.Droid/Properties/AndroidManifest.xml @@ -1,6 +1,7 @@  - - - - \ No newline at end of file + + + + + diff --git a/src/SamplesApp/SamplesApp.UWP/SamplesApp.UWP.csproj b/src/SamplesApp/SamplesApp.UWP/SamplesApp.UWP.csproj index 3f8a47b4a7db..90826fce200c 100644 --- a/src/SamplesApp/SamplesApp.UWP/SamplesApp.UWP.csproj +++ b/src/SamplesApp/SamplesApp.UWP/SamplesApp.UWP.csproj @@ -109,9 +109,6 @@ 1.28.0-dev.86 - - - @@ -134,6 +131,14 @@ Uno.UI.Toolkit + + + + + + Windows Mobile Extensions for the UWP + + diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems index 57cd9fb250ee..86159d7da38e 100644 --- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems +++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems @@ -33,6 +33,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -2052,6 +2056,9 @@ DisplayInformation_Properties.xaml + + Devices_Notifications_VibrationDevice.xaml + Persistence.xaml diff --git a/src/SamplesApp/UITests.Shared/Windows_Phone/Devices_Notifications_VibrationDevice.xaml b/src/SamplesApp/UITests.Shared/Windows_Phone/Devices_Notifications_VibrationDevice.xaml new file mode 100644 index 000000000000..ee618d002e23 --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Windows_Phone/Devices_Notifications_VibrationDevice.xaml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/src/SamplesApp/UITests.Shared/Windows_Phone/Devices_Notifications_VibrationDevice.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_Phone/Devices_Notifications_VibrationDevice.xaml.cs new file mode 100644 index 000000000000..f28315627618 --- /dev/null +++ b/src/SamplesApp/UITests.Shared/Windows_Phone/Devices_Notifications_VibrationDevice.xaml.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Uno.UI.Samples.Controls; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Windows.Foundation.Metadata; +using Windows.Phone.Devices.Notification; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; + +// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 + +namespace UITests.Shared.Windows_Phone +{ + [SampleControlInfo("Windows.Phone", "Devices.Notifications.VibrationDevice", description: "Verifies the Windows.Phone.Devices.Notifications.VibrationDevice API")] + public sealed partial class Devices_Notifications_VibrationDevice : UserControl + { + private VibrationDevice _vibrationDevice; + + public Devices_Notifications_VibrationDevice() + { + this.InitializeComponent(); + if (ApiInformation.IsTypePresent("Windows.Phone.Devices.Notification.VibrationDevice")) + { + try + { + _vibrationDevice = VibrationDevice.GetDefault(); + if (_vibrationDevice == null) + { + ErrorMessage.Text = "VibrationDevice not available"; + } + } + catch (Exception ex) + { + ErrorMessage.Text = ex.Message; + } + } + else + { + ErrorMessage.Text = "VibrationDevice API not present"; + } + } + + private void Vibrate_Click(object sender, RoutedEventArgs e) + { + if (int.TryParse(VibrationDurationTextBox.Text, out int milliseconds)) + { + try + { + _vibrationDevice?.Vibrate(TimeSpan.FromMilliseconds(milliseconds)); + } + catch (Exception ex) + { + ErrorMessage.Text = ex.Message; + } + } + } + + private void Cancel_Click(object sender, RoutedEventArgs e) + { + if (int.TryParse(VibrationDurationTextBox.Text, out int milliseconds)) + { + try + { + _vibrationDevice?.Cancel(); + } + catch (Exception ex) + { + ErrorMessage.Text = ex.Message; + } + } + } + } +} diff --git a/src/Uno.UI.Wasm/WasmScripts/Uno.UI.d.ts b/src/Uno.UI.Wasm/WasmScripts/Uno.UI.d.ts index 7aee2b078ca6..eefcc827cd4a 100644 --- a/src/Uno.UI.Wasm/WasmScripts/Uno.UI.d.ts +++ b/src/Uno.UI.Wasm/WasmScripts/Uno.UI.d.ts @@ -761,3 +761,9 @@ declare namespace Windows.UI.Core { private clearStack; } } +declare namespace Windows.Phone.Devices.Notification { + class VibrationDevice { + static initialize(): boolean; + static vibrate(duration: number): boolean; + } +} diff --git a/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js b/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js index d1c44dd801bb..1f6dcb585cea 100644 --- a/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js +++ b/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js @@ -2176,3 +2176,28 @@ var Windows; })(Core = UI.Core || (UI.Core = {})); })(UI = Windows.UI || (Windows.UI = {})); })(Windows || (Windows = {})); +var Windows; +(function (Windows) { + var Phone; + (function (Phone) { + var Devices; + (function (Devices) { + var Notification; + (function (Notification) { + class VibrationDevice { + static initialize() { + navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate; + if (navigator.vibrate) { + return true; + } + return false; + } + static vibrate(duration) { + return window.navigator.vibrate(duration); + } + } + Notification.VibrationDevice = VibrationDevice; + })(Notification = Devices.Notification || (Devices.Notification = {})); + })(Devices = Phone.Devices || (Phone.Devices = {})); + })(Phone = Windows.Phone || (Windows.Phone = {})); +})(Windows || (Windows = {})); diff --git a/src/Uno.UI.Wasm/ts/Windows/Phone/Devices/Notification/VibrationDevice.ts b/src/Uno.UI.Wasm/ts/Windows/Phone/Devices/Notification/VibrationDevice.ts new file mode 100644 index 000000000000..5c071462a0ec --- /dev/null +++ b/src/Uno.UI.Wasm/ts/Windows/Phone/Devices/Notification/VibrationDevice.ts @@ -0,0 +1,22 @@ +interface Navigator { + webkitVibrate(pattern: number | number[]): boolean; + mozVibrate(pattern: number | number[]): boolean; + msVibrate(pattern: number | number[]): boolean; +} + +namespace Windows.Phone.Devices.Notification { + + export class VibrationDevice { + public static initialize(): boolean { + navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate; + if (navigator.vibrate) { + return true; + } + return false; + } + + public static vibrate(duration: number): boolean { + return window.navigator.vibrate(duration); + } + } +} diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Phone.Devices.Notification/VibrationDevice.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Phone.Devices.Notification/VibrationDevice.cs index 44cf890788ff..aceec0a2282b 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Phone.Devices.Notification/VibrationDevice.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Phone.Devices.Notification/VibrationDevice.cs @@ -2,26 +2,26 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Phone.Devices.Notification { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || false || __MACOS__ [global::Uno.NotImplemented] #endif public partial class VibrationDevice { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || false || __MACOS__ [global::Uno.NotImplemented] public void Vibrate( global::System.TimeSpan duration) { global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Phone.Devices.Notification.VibrationDevice", "void VibrationDevice.Vibrate(TimeSpan duration)"); } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ + #if false || __IOS__ || NET461 || false || __MACOS__ [global::Uno.NotImplemented] public void Cancel() { global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Phone.Devices.Notification.VibrationDevice", "void VibrationDevice.Cancel()"); } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || false || __MACOS__ [global::Uno.NotImplemented] public static global::Windows.Phone.Devices.Notification.VibrationDevice GetDefault() { diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Display/DisplayRequest.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Display/DisplayRequest.cs index 22d0c1d0d5d7..bc2433248e20 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Display/DisplayRequest.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Display/DisplayRequest.cs @@ -2,7 +2,7 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.System.Display { - #if false || false || NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || __WASM__ || __MACOS__ [global::Uno.NotImplemented] #endif public partial class DisplayRequest @@ -15,14 +15,14 @@ public DisplayRequest() } #endif // Forced skipping of method Windows.System.Display.DisplayRequest.DisplayRequest() - #if false || false || NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || __WASM__ || __MACOS__ [global::Uno.NotImplemented] public void RequestActive() { global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.System.Display.DisplayRequest", "void DisplayRequest.RequestActive()"); } #endif - #if false || false || NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || __WASM__ || __MACOS__ [global::Uno.NotImplemented] public void RequestRelease() { diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/BatteryStatus.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/BatteryStatus.cs index ad82d729a99d..52ff533946de 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/BatteryStatus.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/BatteryStatus.cs @@ -2,24 +2,16 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.System.Power { -#if false || false || false || false || false -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ + #if false || false || false || false || false + #if false || false || false || false || false [global::Uno.NotImplemented] -#endif + #endif public enum BatteryStatus { -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ - NotPresent, -#endif -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ - Discharging, -#endif -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ - Idle, -#endif -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ - Charging, -#endif + // Skipping already declared field Windows.System.Power.BatteryStatus.NotPresent + // Skipping already declared field Windows.System.Power.BatteryStatus.Discharging + // Skipping already declared field Windows.System.Power.BatteryStatus.Idle + // Skipping already declared field Windows.System.Power.BatteryStatus.Charging } -#endif + #endif } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/EnergySaverStatus.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/EnergySaverStatus.cs index 1978411e2170..766b087b012b 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/EnergySaverStatus.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/EnergySaverStatus.cs @@ -2,21 +2,15 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.System.Power { -#if false || false || false || false || false -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ + #if false || false || false || false || false + #if false || false || false || false || false [global::Uno.NotImplemented] -#endif + #endif public enum EnergySaverStatus { -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ - Disabled, -#endif -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ - Off, -#endif -#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ - On, -#endif + // Skipping already declared field Windows.System.Power.EnergySaverStatus.Disabled + // Skipping already declared field Windows.System.Power.EnergySaverStatus.Off + // Skipping already declared field Windows.System.Power.EnergySaverStatus.On } -#endif + #endif } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerManager.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerManager.cs index f0b5de9d8a7a..256481ff30cb 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerManager.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerManager.cs @@ -2,7 +2,7 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.System.Power { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || __WASM__ || __MACOS__ [global::Uno.NotImplemented] #endif public partial class PowerManager @@ -17,7 +17,7 @@ public partial class PowerManager } } #endif - #if false || false|| NET461 || __WASM__ || __MACOS__ + #if false || false || NET461 || __WASM__ || __MACOS__ [global::Uno.NotImplemented] public static global::Windows.System.Power.EnergySaverStatus EnergySaverStatus { diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerSupplyStatus.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerSupplyStatus.cs index a8a4b7f2cfc7..0cbfb7e4aae7 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerSupplyStatus.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.System.Power/PowerSupplyStatus.cs @@ -8,15 +8,9 @@ namespace Windows.System.Power #endif public enum PowerSupplyStatus { -#if false || false || false || false || false - NotPresent, -#endif -#if false || false || false || false || false - Inadequate, -#endif -#if false || false || false || false || false - Adequate, -#endif + // Skipping already declared field Windows.System.Power.PowerSupplyStatus.NotPresent + // Skipping already declared field Windows.System.Power.PowerSupplyStatus.Inadequate + // Skipping already declared field Windows.System.Power.PowerSupplyStatus.Adequate } #endif } diff --git a/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.Android.cs b/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.Android.cs new file mode 100644 index 000000000000..cccebdfea576 --- /dev/null +++ b/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.Android.cs @@ -0,0 +1,59 @@ +#if __ANDROID__ +using System; +using System.Collections.Generic; +using System.Text; +using Android.App; +using Android.Content; +using Android.OS; +using Android.Support.V4.Content; + +namespace Windows.Phone.Devices.Notification +{ + public partial class VibrationDevice + { + private const string Permission = "android.permission.VIBRATE"; + private static VibrationDevice _instance; + private static bool _initializationAttempted; + + private readonly Vibrator _vibrator; + + private VibrationDevice(Vibrator vibrator) => + _vibrator = vibrator; + + public static VibrationDevice GetDefault() + { + if (!_initializationAttempted && _instance == null) + { + if (ContextCompat.CheckSelfPermission(Application.Context, Permission) == Android.Content.PM.Permission.Denied) + { + throw new InvalidOperationException($"{Permission} needs to be declared in AndroidManifest.xml"); + } + var vibrator = Application.Context.GetSystemService(Context.VibratorService) as Vibrator; + if (vibrator != null && vibrator.HasVibrator) + { + _instance = new VibrationDevice(vibrator); + } + _initializationAttempted = true; + } + return _instance; + } + + public void Vibrate(TimeSpan duration) + { + var time = (long)duration.TotalMilliseconds; + if (Build.VERSION.SdkInt >= BuildVersionCodes.O) + { + _vibrator.Vibrate(VibrationEffect.CreateOneShot(time, VibrationEffect.DefaultAmplitude)); + } + else + { +#pragma warning disable CS0618 // Type or member is obsolete + _vibrator.Vibrate(time); +#pragma warning restore CS0618 // Type or member is obsolete + } + } + + public void Cancel() => _vibrator.Cancel(); + } +} +#endif diff --git a/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.iOS.cs b/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.iOS.cs new file mode 100644 index 000000000000..48a7a554105a --- /dev/null +++ b/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.iOS.cs @@ -0,0 +1,43 @@ +#if __IOS__ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AudioToolbox; +using UIKit; + +namespace Windows.Phone.Devices.Notification +{ + public partial class VibrationDevice + { + private const int PopSoundId = 1520; + private static VibrationDevice _instance = null; + + private VibrationDevice() + { + } + + public static VibrationDevice GetDefault() => + _instance ?? (_instance = new VibrationDevice()); + + /// + /// iOS vibration support is quite limited, + /// we can produce only very short vibration and one second vibration + /// + /// + public async void Vibrate(TimeSpan duration) + { + if (duration.TotalMilliseconds < 200) + { + var pop = new SystemSound(PopSoundId); + pop.PlaySystemSound(); + } + else + { + SystemSound.Vibrate.PlaySystemSound(); + } + } + } +} +#endif diff --git a/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.wasm.cs b/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.wasm.cs new file mode 100644 index 000000000000..653fcecda0cb --- /dev/null +++ b/src/Uno.UWP/Phone/Devices/Notification/VibrationDevice.wasm.cs @@ -0,0 +1,46 @@ +#if __WASM__ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.Phone.Devices.Notification +{ + public partial class VibrationDevice + { + private const string JsType = "Windows.Phone.Devices.Notification.VibrationDevice"; + private static VibrationDevice _instance = null; + private static bool _initializationAttempted = false; + + private VibrationDevice() + { + } + + public static VibrationDevice GetDefault() + { + if (!_initializationAttempted && _instance == null) + { + var command = $"{JsType}.initialize()"; + var initialized = Uno.Foundation.WebAssemblyRuntime.InvokeJS(command); + if (bool.Parse(initialized) == true) + { + _instance = new VibrationDevice(); + } + _initializationAttempted = true; + } + return _instance; + } + + public void Vibrate(TimeSpan duration) => + WasmVibrate(duration); + + public void Cancel() => + WasmVibrate(TimeSpan.Zero); + + private void WasmVibrate(TimeSpan duration) + { + var command = $"{JsType}.vibrate(\"{(long)duration.TotalMilliseconds}\");"; + Uno.Foundation.WebAssemblyRuntime.InvokeJS(command); + } + } +} +#endif