diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index edb70cab2421..36fd6af2a16d 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"microsoft.dotnet.xharness.cli": {
- "version": "1.0.0-prerelease.22569.1",
+ "version": "1.0.0-prerelease.23110.1",
"commands": [
"xharness"
]
diff --git a/.editorconfig b/.editorconfig
index a303b1fe982b..b864e8f4f202 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -27,6 +27,7 @@ dotnet_diagnostic.IL2050.severity = none
# Code analyzers
dotnet_diagnostic.CA1307.severity = error
dotnet_diagnostic.CA1309.severity = error
+dotnet_diagnostic.CA1815.severity = error
# Modifier preferences
dotnet_style_require_accessibility_modifiers = never:suggestion
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 63fa671206d3..fea2ff84f841 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -18,7 +18,7 @@ Have a look at our [Development Guide](DEVELOPMENT.md) to learn about setting up
### What to work on
-If you're looking for something to work on, please browse our [Handler Property Backlog](https://github.com/dotnet/maui/projects/4). Any issue that is not already assigned is up for grabs. Make sure to read over the [Handler Property PR Guidelines](https://github.com/dotnet/maui/wiki/Handler-Property-PR-Guidelines) to acquaint yourself on how you can get started in contributing to our handler conversion efforts. Included is also a sample PR you can model after.
+If you're looking for something to work on, please browse our [backlog](https://github.com/dotnet/maui/issues?q=is%3Aopen+is%3Aissue+milestone%3ABacklog). Any issue that is not already assigned is up for grabs.
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:
@@ -29,7 +29,7 @@ Read and follow our [Pull Request template](PULL_REQUEST_TEMPLATE.md).
### Pull Request Requirements
-Please refer to our [Handler Property PR Guidelines](https://github.com/dotnet/maui/wiki/Handler-Property-PR-Guidelines) and [Pull Request template](PULL_REQUEST_TEMPLATE.md).
+Please refer to our [Pull Request template](PULL_REQUEST_TEMPLATE.md).
Please check the "Allow edits from maintainers" checkbox on your pull request. This allows us to quickly make minor fixes and resolve conflicts for you.
diff --git a/.github/fabricbot.json b/.github/fabricbot.json
index 0a54f967ad59..22ba6d9c744a 100644
--- a/.github/fabricbot.json
+++ b/.github/fabricbot.json
@@ -2005,116 +2005,12 @@
{
"name": "addReply",
"parameters": {
- "comment": "Thanks for the issue report @${issueAuthor}! This issue appears to be a problem with Visual Studio, so we ask that you use the VS feedback tool to report the issue. That way it will get to the routed to the team that owns this experience in VS.\n\nIf you encounter a problem with Visual Studio, we want to know about it so that we can diagnose and fix it. By using the Report a Problem tool, you can collect detailed information about the problem, and send it to Microsoft with just a few button clicks.\n\n1. Go to the [Visual Studio for Windows feedback tool](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio?view=vs-2022) or [Visual Studio for Mac feedback tool](https://learn.microsoft.com/en-us/visualstudio/mac/report-a-problem?view=vsmac-2022) to report the issue\n2. Close this bug, and consider adding a link to the VS Feedback issue so that others can follow its activity there.\n\nThis issue will be automatically closed in 3 days if there are no further comments."
+ "comment": "Thanks for the issue report @${issueAuthor}! This issue appears to be a problem with Visual Studio, so we ask that you use the VS feedback tool to report the issue. That way it will get to the routed to the team that owns this experience in VS.\n\nIf you encounter a problem with Visual Studio, we want to know about it so that we can diagnose and fix it. By using the Report a Problem tool, you can collect detailed information about the problem, and send it to Microsoft with just a few button clicks.\n\n1. Go to the [Visual Studio for Windows feedback tool](https://docs.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio?view=vs-2022) or [Visual Studio for Mac feedback tool](https://learn.microsoft.com/en-us/visualstudio/mac/report-a-problem?view=vsmac-2022) to report the issue\n2. Close this bug, and consider adding a link to the VS Feedback issue so that others can follow its activity there."
}
}
]
}
},
- {
- "taskType": "scheduled",
- "capabilityId": "ScheduledSearch",
- "subCapability": "ScheduledSearch",
- "version": "1.1",
- "config": {
- "frequency": [
- {
- "weekDay": 0,
- "hours": [
- 0,
- 6,
- 12,
- 18
- ]
- },
- {
- "weekDay": 1,
- "hours": [
- 0,
- 6,
- 12,
- 18
- ]
- },
- {
- "weekDay": 2,
- "hours": [
- 0,
- 6,
- 12,
- 18
- ]
- },
- {
- "weekDay": 3,
- "hours": [
- 0,
- 6,
- 12,
- 18
- ]
- },
- {
- "weekDay": 4,
- "hours": [
- 0,
- 6,
- 12,
- 18
- ]
- },
- {
- "weekDay": 5,
- "hours": [
- 0,
- 6,
- 12,
- 18
- ]
- },
- {
- "weekDay": 6,
- "hours": [
- 0,
- 6,
- 12,
- 18
- ]
- }
- ],
- "searchTerms": [
- {
- "name": "isOpen",
- "parameters": {}
- },
- {
- "name": "hasLabel",
- "parameters": {
- "label": "s/move-to-vs-feedback"
- }
- },
- {
- "name": "noActivitySince",
- "parameters": {
- "days": 3
- }
- }
- ],
- "taskName": "Close 's/move-to-vs-feedback' after 3 days of no activity",
- "actions": [
- {
- "name": "addReply",
- "parameters": {
- "comment": "This issue is being closed due to inactivity. If this issue is still affecting you, please follow the steps above to use the VS Feedback Tool to report the issue."
- }
- },
- {
- "name": "closeIssue",
- "parameters": {}
- }
- ]
- }
- },
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
diff --git a/.github/workflows/dotnet-autoformat-pr-push.yml b/.github/workflows/dotnet-autoformat-pr-push.yml
index 36bbec44475a..7eaab91d8e9f 100644
--- a/.github/workflows/dotnet-autoformat-pr-push.yml
+++ b/.github/workflows/dotnet-autoformat-pr-push.yml
@@ -18,6 +18,7 @@ jobs:
github.event.workflow_run.conclusion == 'success'
steps:
- name: 'Push autoformatted patch'
- uses: rolfbjarne/autoformat-push@v0.1
+ uses: rolfbjarne/autoformat-push@v0.2
with:
- githubToken: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+ githubToken: ${{ secrets.GITHUB_TOKEN }}
+ commentContents: 'Thank you for your pull request. We are auto-formating your source code to follow our code guidelines.'
diff --git a/.github/workflows/dotnet-autoformat-pr.yml b/.github/workflows/dotnet-autoformat-pr.yml
index e94963a536df..dcb055c50335 100644
--- a/.github/workflows/dotnet-autoformat-pr.yml
+++ b/.github/workflows/dotnet-autoformat-pr.yml
@@ -14,7 +14,6 @@ jobs:
- name: 'Autoformat'
uses: rolfbjarne/autoformat@v0.2
with:
- script: 'dotnet format .\Microsoft.Maui.sln --no-restore --exclude Templates/src BlazorWebView/src/SharedSource/BlazorWebViewDeveloperTools.cs BlazorWebView/src/SharedSource/BlazorWebViewServiceCollectionExtensions.cs Graphics/src/Graphics.Win2D/W2DCanvas.cs Graphics/src/Graphics.Win2D/W2DExtensions.cs'
- projects: "Microsoft.Maui.sln"
+ script: 'dotnet format Microsoft.Maui.sln --no-restore --exclude Templates/src BlazorWebView/src/SharedSource/BlazorWebViewDeveloperTools.cs BlazorWebView/src/SharedSource/BlazorWebViewServiceCollectionExtensions.cs Graphics/src/Graphics.Win2D/W2DCanvas.cs Graphics/src/Graphics.Win2D/W2DExtensions.cs'
onlyFilesModifiedInPullRequest: true
- git_commit_message: 'Thank you for your pull request. We are auto-formating your source code to follow our code guidelines.'
+ git_commit_message: 'Auto-format source code'
diff --git a/.gitignore b/.gitignore
index ca39706b101e..7ed3d08b1787 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,10 +3,8 @@
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
-.nuspec/**/*.dll
-.nuspec/**/*.dylib
-.nuspec/**/*.so
-.XamarinFormsVersionFile.txt
+.nuspec/
+.buildtasks/
templatesTest/
# User-specific files
diff --git a/.nuspec/AutoImport.InTree.props b/.nuspec/AutoImport.InTree.props
deleted file mode 100644
index 449b9845588e..000000000000
--- a/.nuspec/AutoImport.InTree.props
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
-
-
-
-
-
- Designer
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- MSBuild:Compile
- $(DefaultXamlRuntime)
-
-
- MSBuild:Compile
- $(DefaultXamlRuntime)
-
-
- MSBuild:Compile
- $(DefaultXamlRuntime)
-
-
-
-
\ No newline at end of file
diff --git a/.nuspec/Microsoft.Maui.Controls.DualScreen.nuspec b/.nuspec/Microsoft.Maui.Controls.DualScreen.nuspec
deleted file mode 100644
index 6391725e89f6..000000000000
--- a/.nuspec/Microsoft.Maui.Controls.DualScreen.nuspec
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
- Xamarin.Forms.DualScreen
- $version$
- Microsoft
- microsoft xamarin
- xamarin forms twopaneview DualScreen xamarinforms xamarinformsdualscreen xamarin.forms.dualscreen
- MIT
- Assets\xamarin_128x128.png
- http://xamarin.com/forms
-
- true
- DualScreen support for Xamarin.Forms
- © Microsoft Corporation. All rights reserved.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.nuspec/Microsoft.Maui.Controls.SingleProject.props b/.nuspec/Microsoft.Maui.Controls.SingleProject.props
deleted file mode 100644
index feeed761bb20..000000000000
--- a/.nuspec/Microsoft.Maui.Controls.SingleProject.props
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
- WinExe
- MSIX
- true
- false
-
- false
- true
- true
- <_SingleProjectRIDRequired Condition="'$(OutputType)' == 'WinExe'">true
- <_SingleProjectRIDSpecified Condition="'$(RuntimeIdentifier)' != '' or '$(RuntimeIdentifiers)' != ''">true
-
-
-
- <_SingleProjectHostArchitecture>$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)
- <_SingleProjectHostArchitecture>$(_SingleProjectHostArchitecture.ToLower())
- win10-$(_SingleProjectHostArchitecture)
- <_MauiUsingDefaultRuntimeIdentifier>true
-
-
-
-
-
-
-
-
-
diff --git a/.nuspec/Microsoft.Maui.Core.props b/.nuspec/Microsoft.Maui.Core.props
deleted file mode 100644
index 805beb40223e..000000000000
--- a/.nuspec/Microsoft.Maui.Core.props
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- true
- $(EnableMsixTooling)
- true
- false
-
-
-
diff --git a/.nuspec/Microsoft.Maui.Core.targets b/.nuspec/Microsoft.Maui.Core.targets
deleted file mode 100644
index faf2349bae2d..000000000000
--- a/.nuspec/Microsoft.Maui.Core.targets
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/.nuspec/_._ b/.nuspec/_._
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/Directory.Build.props b/Directory.Build.props
index 008616235f54..8933b3839956 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -14,13 +14,21 @@
<_MauiPreviousDotNetTfm Condition="'$(_MauiPreviousDotNetTfm)' == ''">net$(_MauiPreviousDotNetVersion)
<_MauiTargetPlatformIdentifier>$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)'))
+ <_MauiNoTargetPlatform>false
<_MauiNoTargetPlatform Condition="'$(_MauiTargetPlatformIdentifier)' == ''">True
+ <_MauiTargetPlatformIsAndroid>false
<_MauiTargetPlatformIsAndroid Condition="'$(_MauiTargetPlatformIdentifier)' == 'android'">True
+ <_MauiTargetPlatformIsiOS>false
<_MauiTargetPlatformIsiOS Condition="'$(_MauiTargetPlatformIdentifier)' == 'ios'">True
+ <_MauiTargetPlatformIsMacCatalyst>false
<_MauiTargetPlatformIsMacCatalyst Condition="'$(_MauiTargetPlatformIdentifier)' == 'maccatalyst'">True
+ <_MauiTargetPlatformIsmacOS>false
<_MauiTargetPlatformIsmacOS Condition="'$(_MauiTargetPlatformIdentifier)' == 'macos'">True
+ <_MauiTargetPlatformIstvOS>false
<_MauiTargetPlatformIstvOS Condition="'$(_MauiTargetPlatformIdentifier)' == 'tvos'">True
+ <_MauiTargetPlatformIsWindows>false
<_MauiTargetPlatformIsWindows Condition="$(_MauiTargetPlatformIdentifier.Contains('windows')) == 'True'">True
+ <_MauiTargetPlatformIsTizen>false
<_MauiTargetPlatformIsTizen Condition="'$(_MauiTargetPlatformIdentifier)' == 'tizen'">True
@@ -109,7 +117,6 @@
$(MSBuildThisFileDirectory)
$(MSBuildThisFileDirectory)src/
- $(MSBuildThisFileDirectory).nuspec/
$(MSBuildThisFileDirectory)bin/
$(DotNetOutputPath)temp/
$(DotNetOutputPath)dotnet/
@@ -119,7 +126,8 @@
$(DotNetDirectory)sdk-manifests/$(DotNetSdkManifestsFolder)/
$(DotNetDirectory)template-packs/
<_MauiBuildTasksLocation>$(_MauiBuildTasksLocation)
- <_MauiBuildTasksLocation Condition="'$(_MauiBuildTasksLocation)' == ''">$(MSBuildThisFileDirectory).nuspec\
+ <_MauiBuildTasksLocation Condition="'$(_MauiBuildTasksLocation)' == ''">$(MSBuildThisFileDirectory).buildtasks\
+ <_MauiAOTProfileLocation>$(MauiSrcDirectory)Controls\src\Build.Tasks\nuget\buildTransitive\netstandard2.0\
true
portable
true
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 65470a9b9367..2005eb8e56bb 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -75,7 +75,7 @@
-
+
diff --git a/Microsoft.Maui-mac.slnf b/Microsoft.Maui-mac.slnf
index c5f706d0729a..8578bcd290cd 100644
--- a/Microsoft.Maui-mac.slnf
+++ b/Microsoft.Maui-mac.slnf
@@ -27,6 +27,7 @@
"src\\Controls\\src\\Build.Tasks\\Controls.Build.Tasks.csproj",
"src\\Controls\\src\\Core.Design\\Controls.Core.Design.csproj",
"src\\Controls\\src\\Core\\Controls.Core.csproj",
+ "src\\Controls\\src\\NuGet\\Controls.NuGet.csproj",
"src\\Controls\\src\\SourceGen\\Controls.SourceGen.csproj",
"src\\Controls\\src\\Xaml.Design\\Controls.Xaml.Design.csproj",
"src\\Controls\\src\\Xaml\\Controls.Xaml.csproj",
@@ -57,12 +58,6 @@
"src\\TestUtils\\src\\DeviceTests.Runners\\TestUtils.DeviceTests.Runners.csproj",
"src\\TestUtils\\src\\DeviceTests\\TestUtils.DeviceTests.csproj",
"src\\TestUtils\\src\\TestUtils\\TestUtils.csproj",
- "src\\Workload\\Microsoft.Maui.Controls.Ref\\Microsoft.Maui.Controls.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Controls.Runtime\\Microsoft.Maui.Controls.Runtime.csproj",
- "src\\Workload\\Microsoft.Maui.Core.Ref\\Microsoft.Maui.Core.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Core.Runtime\\Microsoft.Maui.Core.Runtime.csproj",
- "src\\Workload\\Microsoft.Maui.Essentials.Ref\\Microsoft.Maui.Essentials.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Essentials.Runtime\\Microsoft.Maui.Essentials.Runtime.csproj",
"src\\Workload\\Microsoft.Maui.Sdk\\Microsoft.Maui.Sdk.csproj",
"src\\Workload\\Microsoft.NET.Sdk.Maui\\Microsoft.NET.Sdk.Maui.csproj"
]
diff --git a/Microsoft.Maui.BuildTasks.slnf b/Microsoft.Maui.BuildTasks.slnf
index 80af361012ad..820dd1bbcdc9 100644
--- a/Microsoft.Maui.BuildTasks.slnf
+++ b/Microsoft.Maui.BuildTasks.slnf
@@ -4,7 +4,10 @@
"projects": [
"src\\Graphics\\src\\Graphics\\Graphics.csproj",
"src\\Controls\\src\\Build.Tasks\\Controls.Build.Tasks.csproj",
+ "src\\Controls\\src\\Core.Design\\Controls.Core.Design.csproj",
"src\\Controls\\src\\Core\\Controls.Core.csproj",
+ "src\\Controls\\src\\NuGet\\Controls.NuGet.csproj",
+ "src\\Controls\\src\\Xaml.Design\\Controls.Xaml.Design.csproj",
"src\\Controls\\src\\Xaml\\Controls.Xaml.csproj",
"src\\Core\\src\\Core.csproj",
"src\\SingleProject\\Resizetizer\\src\\Resizetizer.csproj"
diff --git a/Microsoft.Maui.Packages-mac.slnf b/Microsoft.Maui.Packages-mac.slnf
index bfb2f5c21bcf..51c79fd590b2 100644
--- a/Microsoft.Maui.Packages-mac.slnf
+++ b/Microsoft.Maui.Packages-mac.slnf
@@ -9,6 +9,7 @@
"src\\Controls\\src\\Build.Tasks\\Controls.Build.Tasks.csproj",
"src\\Controls\\src\\Core.Design\\Controls.Core.Design.csproj",
"src\\Controls\\src\\Core\\Controls.Core.csproj",
+ "src\\Controls\\src\\NuGet\\Controls.NuGet.csproj",
"src\\Controls\\src\\SourceGen\\Controls.SourceGen.csproj",
"src\\Controls\\src\\Xaml.Design\\Controls.Xaml.Design.csproj",
"src\\Controls\\src\\Xaml\\Controls.Xaml.csproj",
@@ -20,13 +21,7 @@
"src\\Graphics\\src\\Text.Markdig\\Graphics.Text.Markdig.csproj",
"src\\SingleProject\\Resizetizer\\src\\Resizetizer.csproj",
"src\\Templates\\src\\Microsoft.Maui.Templates.csproj",
- "src\\Workload\\Microsoft.Maui.Controls.Ref\\Microsoft.Maui.Controls.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Controls.Runtime\\Microsoft.Maui.Controls.Runtime.csproj",
"src\\Workload\\Microsoft.Maui.Sdk\\Microsoft.Maui.Sdk.csproj",
- "src\\Workload\\Microsoft.Maui.Core.Ref\\Microsoft.Maui.Core.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Core.Runtime\\Microsoft.Maui.Core.Runtime.csproj",
- "src\\Workload\\Microsoft.Maui.Essentials.Ref\\Microsoft.Maui.Essentials.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Essentials.Runtime\\Microsoft.Maui.Essentials.Runtime.csproj",
"src\\Workload\\Microsoft.NET.Sdk.Maui\\Microsoft.NET.Sdk.Maui.csproj"
]
}
diff --git a/Microsoft.Maui.Packages.slnf b/Microsoft.Maui.Packages.slnf
index c28b36f80843..76bd81f1b7bb 100644
--- a/Microsoft.Maui.Packages.slnf
+++ b/Microsoft.Maui.Packages.slnf
@@ -11,6 +11,7 @@
"src\\Controls\\src\\Build.Tasks\\Controls.Build.Tasks.csproj",
"src\\Controls\\src\\Core.Design\\Controls.Core.Design.csproj",
"src\\Controls\\src\\Core\\Controls.Core.csproj",
+ "src\\Controls\\src\\NuGet\\Controls.NuGet.csproj",
"src\\Controls\\src\\SourceGen\\Controls.SourceGen.csproj",
"src\\Controls\\src\\Xaml.Design\\Controls.Xaml.Design.csproj",
"src\\Controls\\src\\Xaml\\Controls.Xaml.csproj",
@@ -23,14 +24,7 @@
"src\\Essentials\\src\\Essentials.csproj",
"src\\SingleProject\\Resizetizer\\src\\Resizetizer.csproj",
"src\\Templates\\src\\Microsoft.Maui.Templates.csproj",
- "src\\Workload\\Microsoft.Maui.Controls.Ref\\Microsoft.Maui.Controls.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Controls.Runtime\\Microsoft.Maui.Controls.Runtime.csproj",
"src\\Workload\\Microsoft.Maui.Sdk\\Microsoft.Maui.Sdk.csproj",
- "src\\Workload\\Microsoft.Maui.Core.Ref\\Microsoft.Maui.Core.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Core.Runtime\\Microsoft.Maui.Core.Runtime.csproj",
- "src\\Workload\\Microsoft.Maui.Essentials.Ref\\Microsoft.Maui.Essentials.Ref.csproj",
- "src\\Workload\\Microsoft.Maui.Essentials.Runtime\\Microsoft.Maui.Essentials.Runtime.csproj",
- "src\\Workload\\Microsoft.Maui.Resizetizer.Sdk\\Microsoft.Maui.Resizetizer.Sdk.csproj",
"src\\Workload\\Microsoft.NET.Sdk.Maui\\Microsoft.NET.Sdk.Maui.csproj"
]
}
diff --git a/Microsoft.Maui.sln b/Microsoft.Maui.sln
index 59a9f74842cc..c57fc12d4936 100644
--- a/Microsoft.Maui.sln
+++ b/Microsoft.Maui.sln
@@ -70,22 +70,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebViewAppShared", "src\Bla
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workload", "Workload", "{EC63FD88-5E12-46D7-B440-68F70241D987}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Controls.Ref", "src\Workload\Microsoft.Maui.Controls.Ref\Microsoft.Maui.Controls.Ref.csproj", "{91B7E807-1026-4238-A7C2-D7A02C66F141}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Controls.Runtime", "src\Workload\Microsoft.Maui.Controls.Runtime\Microsoft.Maui.Controls.Runtime.csproj", "{9D8171BD-0F66-4D97-9A38-46800FC6B710}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Sdk", "src\Workload\Microsoft.Maui.Sdk\Microsoft.Maui.Sdk.csproj", "{C5C434A7-4E1F-456F-A23A-F2566C98301A}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Core.Ref", "src\Workload\Microsoft.Maui.Core.Ref\Microsoft.Maui.Core.Ref.csproj", "{359FFDAC-3E3C-4A78-98EE-9070841E5792}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Core.Runtime", "src\Workload\Microsoft.Maui.Core.Runtime\Microsoft.Maui.Core.Runtime.csproj", "{73075C7E-AA0A-4FD6-BBD7-6BD3B43BC2A9}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Essentials.Ref", "src\Workload\Microsoft.Maui.Essentials.Ref\Microsoft.Maui.Essentials.Ref.csproj", "{28B1E6A8-4EB7-4B82-9552-10C418692496}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Essentials.Runtime", "src\Workload\Microsoft.Maui.Essentials.Runtime\Microsoft.Maui.Essentials.Runtime.csproj", "{C69336DF-EE56-4236-8188-06B2A8AD8A36}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Maui.Resizetizer.Sdk", "src\Workload\Microsoft.Maui.Resizetizer.Sdk\Microsoft.Maui.Resizetizer.Sdk.csproj", "{02414DF4-FBE9-400B-8F3F-40DDC7F8FEFC}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Maui", "src\Workload\Microsoft.NET.Sdk.Maui\Microsoft.NET.Sdk.Maui.csproj", "{081EE5E5-69D4-493C-9EB4-47423C4728AB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtils.DeviceTests.Runners", "src\TestUtils\src\DeviceTests.Runners\TestUtils.DeviceTests.Runners.csproj", "{316C0861-069B-4572-879F-F01E568F33A2}"
@@ -253,6 +239,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GraphicsTester.Skia.Gtk", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.Core.Design.UnitTests", "src\Controls\tests\Core.Design.UnitTests\Controls.Core.Design.UnitTests.csproj", "{F68932B0-81A2-4CC3-A4F7-28091EE91B23}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls.NuGet", "src\Controls\src\NuGet\Controls.NuGet.csproj", "{4A6930AE-B67C-4D29-B1A8-ED9EB7F923A7}"
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core.DeviceTests.Shared", "src\Core\tests\DeviceTests.Shared\Core.DeviceTests.Shared.csproj", "{66CC98E3-6A1A-4C44-A23C-B575E82106EC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graphics.DeviceTests", "src\Graphics\tests\DeviceTests\Graphics.DeviceTests.csproj", "{34969E49-FA6E-41BB-9813-5689BB14021E}"
@@ -337,38 +325,10 @@ Global
{9F1E0CE0-BF56-433F-8238-6C2B880EEF18}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F1E0CE0-BF56-433F-8238-6C2B880EEF18}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F1E0CE0-BF56-433F-8238-6C2B880EEF18}.Release|Any CPU.Build.0 = Release|Any CPU
- {91B7E807-1026-4238-A7C2-D7A02C66F141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {91B7E807-1026-4238-A7C2-D7A02C66F141}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {91B7E807-1026-4238-A7C2-D7A02C66F141}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {91B7E807-1026-4238-A7C2-D7A02C66F141}.Release|Any CPU.Build.0 = Release|Any CPU
- {9D8171BD-0F66-4D97-9A38-46800FC6B710}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9D8171BD-0F66-4D97-9A38-46800FC6B710}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9D8171BD-0F66-4D97-9A38-46800FC6B710}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9D8171BD-0F66-4D97-9A38-46800FC6B710}.Release|Any CPU.Build.0 = Release|Any CPU
{C5C434A7-4E1F-456F-A23A-F2566C98301A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C5C434A7-4E1F-456F-A23A-F2566C98301A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C5C434A7-4E1F-456F-A23A-F2566C98301A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5C434A7-4E1F-456F-A23A-F2566C98301A}.Release|Any CPU.Build.0 = Release|Any CPU
- {359FFDAC-3E3C-4A78-98EE-9070841E5792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {359FFDAC-3E3C-4A78-98EE-9070841E5792}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {359FFDAC-3E3C-4A78-98EE-9070841E5792}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {359FFDAC-3E3C-4A78-98EE-9070841E5792}.Release|Any CPU.Build.0 = Release|Any CPU
- {73075C7E-AA0A-4FD6-BBD7-6BD3B43BC2A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {73075C7E-AA0A-4FD6-BBD7-6BD3B43BC2A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {73075C7E-AA0A-4FD6-BBD7-6BD3B43BC2A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {73075C7E-AA0A-4FD6-BBD7-6BD3B43BC2A9}.Release|Any CPU.Build.0 = Release|Any CPU
- {28B1E6A8-4EB7-4B82-9552-10C418692496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {28B1E6A8-4EB7-4B82-9552-10C418692496}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {28B1E6A8-4EB7-4B82-9552-10C418692496}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {28B1E6A8-4EB7-4B82-9552-10C418692496}.Release|Any CPU.Build.0 = Release|Any CPU
- {C69336DF-EE56-4236-8188-06B2A8AD8A36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C69336DF-EE56-4236-8188-06B2A8AD8A36}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C69336DF-EE56-4236-8188-06B2A8AD8A36}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C69336DF-EE56-4236-8188-06B2A8AD8A36}.Release|Any CPU.Build.0 = Release|Any CPU
- {02414DF4-FBE9-400B-8F3F-40DDC7F8FEFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {02414DF4-FBE9-400B-8F3F-40DDC7F8FEFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {02414DF4-FBE9-400B-8F3F-40DDC7F8FEFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {02414DF4-FBE9-400B-8F3F-40DDC7F8FEFC}.Release|Any CPU.Build.0 = Release|Any CPU
{081EE5E5-69D4-493C-9EB4-47423C4728AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{081EE5E5-69D4-493C-9EB4-47423C4728AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{081EE5E5-69D4-493C-9EB4-47423C4728AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -635,6 +595,10 @@ Global
{F68932B0-81A2-4CC3-A4F7-28091EE91B23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F68932B0-81A2-4CC3-A4F7-28091EE91B23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F68932B0-81A2-4CC3-A4F7-28091EE91B23}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4A6930AE-B67C-4D29-B1A8-ED9EB7F923A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4A6930AE-B67C-4D29-B1A8-ED9EB7F923A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4A6930AE-B67C-4D29-B1A8-ED9EB7F923A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4A6930AE-B67C-4D29-B1A8-ED9EB7F923A7}.Release|Any CPU.Build.0 = Release|Any CPU
{66CC98E3-6A1A-4C44-A23C-B575E82106EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66CC98E3-6A1A-4C44-A23C-B575E82106EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66CC98E3-6A1A-4C44-A23C-B575E82106EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -675,14 +639,7 @@ Global
{05DB57B8-D0A5-499B-AD35-7093C2E9C9D7} = {E25E7929-2423-4C8A-9B03-DC4C8B19A2E5}
{A8E9400E-70DD-421F-8609-1C2FA4AE8E71} = {1614D1A4-5C3D-4D5B-8C89-426E37A564EF}
{9F1E0CE0-BF56-433F-8238-6C2B880EEF18} = {A8E9400E-70DD-421F-8609-1C2FA4AE8E71}
- {91B7E807-1026-4238-A7C2-D7A02C66F141} = {EC63FD88-5E12-46D7-B440-68F70241D987}
- {9D8171BD-0F66-4D97-9A38-46800FC6B710} = {EC63FD88-5E12-46D7-B440-68F70241D987}
{C5C434A7-4E1F-456F-A23A-F2566C98301A} = {EC63FD88-5E12-46D7-B440-68F70241D987}
- {359FFDAC-3E3C-4A78-98EE-9070841E5792} = {EC63FD88-5E12-46D7-B440-68F70241D987}
- {73075C7E-AA0A-4FD6-BBD7-6BD3B43BC2A9} = {EC63FD88-5E12-46D7-B440-68F70241D987}
- {28B1E6A8-4EB7-4B82-9552-10C418692496} = {EC63FD88-5E12-46D7-B440-68F70241D987}
- {C69336DF-EE56-4236-8188-06B2A8AD8A36} = {EC63FD88-5E12-46D7-B440-68F70241D987}
- {02414DF4-FBE9-400B-8F3F-40DDC7F8FEFC} = {EC63FD88-5E12-46D7-B440-68F70241D987}
{081EE5E5-69D4-493C-9EB4-47423C4728AB} = {EC63FD88-5E12-46D7-B440-68F70241D987}
{316C0861-069B-4572-879F-F01E568F33A2} = {7AC28763-9C68-4BF9-A1BA-25CBFFD2D15C}
{E87D865B-4EA8-4A30-B6C1-572D2061D707} = {7AC28763-9C68-4BF9-A1BA-25CBFFD2D15C}
@@ -762,6 +719,7 @@ Global
{F26D31D3-CE4C-4F32-A77F-E2905C948674} = {42AB9AE1-631D-4AD4-85B7-910FF0940BDB}
{F351A992-18E4-473C-8ADD-2BA0BAA7B5A2} = {1BA0121E-0B83-4C8F-81BE-C293E7E35DCE}
{F68932B0-81A2-4CC3-A4F7-28091EE91B23} = {25D0D27A-C5FE-443D-8B65-D6C987F4A80E}
+ {4A6930AE-B67C-4D29-B1A8-ED9EB7F923A7} = {50C758FE-4E10-409A-94F5-A75480960864}
{66CC98E3-6A1A-4C44-A23C-B575E82106EC} = {C564DDD6-DE79-45CD-88EA-3F690481572A}
{34969E49-FA6E-41BB-9813-5689BB14021E} = {936C47A9-A7EA-4FBD-8733-CED1D4100E69}
EndGlobalSection
diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT
index ccc2d383f7f2..58bb1b5a09e9 100644
--- a/THIRD-PARTY-NOTICES.TXT
+++ b/THIRD-PARTY-NOTICES.TXT
@@ -465,3 +465,31 @@ License notice for Gradle (https://github.com/gradle/gradle)
==============================================================================
+
+License notice for IQKeyboardManager
+=========================================
+
+(https://github.com/hackiftekhar/IQKeyboardManager/blob/master/LICENSE.md)
+
+MIT License
+
+Copyright (c) 2013-2017 Iftekhar Qurashi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+=========================================
diff --git a/cSpell.json b/cSpell.json
index 980bfd275013..026be1843be9 100644
--- a/cSpell.json
+++ b/cSpell.json
@@ -2,7 +2,11 @@
"version": "0.2",
"language": "en",
"words": [
- "Blazor"
+ "Blazor",
+ "Skia",
+ "Resizetizer",
+ "nugets",
+ "netstandard"
],
"ignoreWords": [],
"patterns": [
diff --git a/docs/design/NuGets.md b/docs/design/NuGets.md
new file mode 100644
index 000000000000..7db4653f76d5
--- /dev/null
+++ b/docs/design/NuGets.md
@@ -0,0 +1,158 @@
+# .NET MAUI NuGet Structure
+
+There are several artifacts in the .NET MAUI "universe":
+
+* Workload packages:
+ * `Microsoft.NET.Sdk.Maui.Manifest` - The workload manifest for the .NET SDK
+ * `Microsoft.Maui.Sdk` - The actual .NET MAUI workload SDK
+ * `Microsoft.Maui.Templates.net*` - The current set of templates for this build of .NET MAUI
+* .NET MAUI framework:
+ * `Microsoft.Maui.Controls` - The super/root package of .NET MAUI Controls
+ * `Microsoft.Maui.Controls.Core` - The Controls assemblies
+ * `Microsoft.Maui.Controls.Xaml` - The XAML parser
+ * `Microsoft.Maui.Controls.Build.Tasks` - The real set of XAML[C|G] targets and globs
+ * `Microsoft.Maui.Resizetizer` - The framework-and-platform-agnostic asset generator and integrator
+ * `Microsoft.Maui.Core` - The base interfaces and handlers for all .NET MAUI things
+ * `Microsoft.Maui.Essentials` - The core set of framework-agnostic, cross-platform APIs
+ * `Microsoft.Maui.Controls.Compatibility` - The set of compatibility APIs for Xamarin.Forms
+* .NET MAUI maps support:
+ * `Microsoft.Maui.Controls.Maps` - The set of XAML-based map controls
+ * `Microsoft.Maui.Maps` - The set of handlers and interfaces for mapping controls
+* .NET MAUI dual-screen / foldable support:
+ * `Microsoft.Maui.Controls.Foldable` - The set of APIs and controls needed for dual-screen support
+* .NET MAUI graphics:
+ * `Microsoft.Maui.Graphics` - The core graphics engine of .NET MAUI
+ * `Microsoft.Maui.Graphics.Win2D.WinUI.Desktop` - The Win2D-based version of the graphics engine (soon to be merged with the core engine)
+ * `Microsoft.Maui.Graphics.Skia` - The SkiaSharp-based version of the graphics engine
+ * `Microsoft.Maui.Graphics.Text.Markdig` - The markdown support for the graphics engine
+* ASP.NET Blazor desktop/mobile support:
+ * `Microsoft.AspNetCore.Components.WebView.Maui` - The BlazorWebView for .NET MAUI apps
+ * `Microsoft.AspNetCore.Components.WebView.WindowsForms` - The BlazorWebView for Windows Forms apps
+ * `Microsoft.AspNetCore.Components.WebView.Wpf` - The BlazorWebView for WPF apps
+
+## Handling .targets and .props
+
+A typical workload has all the targets in the "SDK" portion and then pulls in a bunch of RID-specific NuGet packages, but for MAUI this is not necessary as the size of the entire workload with all the packs is about 60MB - with about 38MB actually just being SkiaSharp for all the platforms in the Resizetizer SDK.
+
+For MAUI, we decided to reduce the number of pack and msi downloads and just go with almost a 1 to 1 csproj to nuget.
+
+Most nugets do not contain or need targets and/or props files, but some do. These include:
+
+ - Workload
+ - Manifest - `Microsoft.NET.Sdk.Maui.Manifest`
+ - SDK - `Microsoft.Maui.Sdk`
+ - NuGet Packages
+ - Controls - `Microsoft.Maui.Controls.Build.Tasks`
+ - Core - `Microsoft.Maui.Core`
+ - Resizetizer - `Microsoft.Maui.Resizetizer`
+
+### Structure of .props & .targets Files
+
+In most cases, there are 4 types of targets/props files:
+
+ - `.props`
+ This file runs before anything and everything (except the `Directory.Build.props`) and can set defaults for the csproj to use.
+ - `.targets`
+ This is the actual start of the targets for the pack. It does at least 2 things:
+ 1. Imports the `.Before.targets` file that runs before any targets run (but after all props have run).
+ 2. Queues up the `.After.targets` file in the `$(AfterMicrosoftNETSdkTargets)` MSBuild property to run after all the targets have been imported. If a nuget needs to have some targets run at this point, then that nuget can append the file to the property:
+ ```xml
+
+ $(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)Microsoft.Maui.[something].After.targets
+
+ ```
+ - `.Before.targets`
+ This file includes anything that is needed in the main targets file, but before any core SDK/platform targets have run. This is often used to set defaults based on values the user has set in the csproj.
+ _This file technically could be merged into `.targets`, but is split out to make the organization of the targets easier._
+ - `.After.targets`
+ This file runs after most of the targets have run - including the core SDK and workloads. This can be used to override any SDK targets or tasks.
+
+### Targets in the Workload
+
+There are 2 components in the workload:
+ - Manifest - `Microsoft.NET.Sdk.Maui.Manifest`
+ - SDK - `Microsoft.Maui.Sdk`
+
+The workload manifest contains the `WorkloadManifest.json` and the `WorkloadManifest.targets` as required by .NET. The .json file is just a tree of all the various components and pack IDs that are needed as part of the MAUI workload. The .targets file is just the entrypoint to the SDK and contains the SDK pack imports for MSBuild.
+
+The SDK pack contains the actual targets and props files. Using a structure similar to the section above, it includes the main parts of the workload things.
+
+There are 2 key files that must be present in a workload:
+ - `AutoImport.props`
+ This file is empty as this is just needed by MSBuild.
+ - `Sdk.targets`
+ This file imports the `BundledVersions.targets` and `Microsoft.Maui.Sdk.targets` files depending on the `UseXxx` MSBuild properties.
+
+The targets file can then import all the SDK:
+ - `BundledVersions.targets`
+ This file sets various version properties and then implicitly imports all the required NuGet packages depending on the `UseXxx` MSBuild properties.
+ - `Microsoft.Maui.Sdk.targets`
+ This is the actual start of the targets for the MAUI framework. It does a few things:
+ 1. Imports the `Microsoft.Maui.Sdk.Before.targets` file that runs before any MAUI targets run (but after all props have run).
+ 2. Imports any targets from the nugets that need to run after the .csproj but before the nuget .targets using the `$(MicrosoftMauiSdkPlatformTargets)` MSBuild property. If a nuget needs to have some targets run at this point, then that nuget can append the file to the property:
+ ```xml
+
+ $(MicrosoftMauiSdkPlatformTargets);$(MSBuildThisFileDirectory)Microsoft.Maui.Sdk.[platform].targets
+
+ ```
+ 3. Queues up the `Microsoft.Maui.Sdk.After.targets` file to run after all the targets have been imported.
+ - `Microsoft.Maui.Sdk.Before.targets`
+ This file sets any pre-nuget-restore properties required by the framework. This currently includes anything that NuGet will use as part of the restore - such as RIDs and R2R values. These properties cannot be in the nugets as restoring the nugets will make it such that the restore state is now invalidated.
+ _This file technically could be merged into `Microsoft.Maui.Sdk.targets`, but is split out to make the organization of the targets easier.
+ - `Microsoft.Maui.Sdk.After.targets`
+ This file runs after most of the targets have run and currently just ensures all the `ProjectCapability` items are included based on the `UseXxx` MSBuild properties. These values are used by the IDE to determine what to do and how to restore. So, these must also be on disk prior to any nuget install.
+
+### Targets in the Packs
+
+There are 3 packs today that need targets:
+
+ - Controls - `Microsoft.Maui.Controls.Build.Tasks`
+ - Core - `Microsoft.Maui.Core`
+ - Resizetizer - `Microsoft.Maui.Resizetizer`
+
+#### Targets in Controls
+
+The Controls section of MAUI is the main set of libraries that a MAUI app uses. The targets and props needed but MAUI mostly live in the `Microsoft.Maui.Controls.Build.Tasks` nuget. This is mainly because of the dependency structure of MAUI.
+
+Controls is the "library name" as well as the assembly name - but the bits we need for the MSBuild tasks depend on this. We _could_ do some funky magic and merge all the components of Controls into a single NuGet, but this is maybe not as worth it. Right now we have a empty NuGet that just pulls in all the things.
+
+But for the targets, this is very similar to the structure mentioned above, but with some platform targets too.
+
+For the files we use, there are 3 areas:
+ - platform targets that set some properties and then import the netstandard targets
+ - netstandard targets that represent the real work
+ - targets as the root that catch any platforms that are not counted as netstandard and just import the netstandard targets
+
+**Platform Files**
+
+If NuGet detects a platform folder in the nuget, then it skips all other imports and just uses the files in there. As a result, the targets files are just dummy/redirection to import the netstandard targets. the props files are where the real customization comes from and is used to set some platform-specific details.
+
+When the targets were all in the workload, they all ran at a point where the TFM could be used. But, when in a NuGet, they run too early so we use the NuGet feature of the TFM loading.
+
+**.NET Standard Files**
+
+This is the real work folder and is just `netstandard` because that is the TFM of the build tasks assembly - and that is just because this needs to be loaded by both the full MSBuild and the dotnet core MSBuild.
+
+These targets follow the structure outlined above with some props files and then the targets files importing a before and after targets. Some of the things that these files do is set the globs and include the various XAML compiler tasks. It also hooks up the analyzers and AOT profiles.
+
+**Root Files**
+
+Some platforms do not count netstandard as part of net7 - such as Windows - so it falls back to nothing. Not sure if this is a bug or a feature, but having files at the root makes sure that _all_ things get _something_.
+
+#### Targets in Core
+
+The targets and props for Core all live in the root of the buildTransitive so that all platforms can have access to them without having to have duplicates or files importing them per TFM. Windows is the exception to this because it has to set some platform-specific properties. There are some Windows-specific targets and tasks in the root, but they are conditioned to the Windows TFM. This makes maintenance easier if everything is in a single file.
+
+Since we have added a Windows TFM folder, NuGet stops looking at the root of the buildTransitive folder for targets and props. As a result, the Windows targets and props just import the root files after setting any platform-specific properties.
+
+The targets and tasks in this NuGet are pretty minimal and really just set some core platform defaults - mainly Windows App SDK properties to control how we want projects to work in .NET MAUI. It also adds some Windows App SDK workarounds for bugs that have not yet reached the public releases.
+
+#### Targets in Resizetizer
+
+The targets and props in Resizetizer are pretty standard and really all fit into 1 file. However, to be consistent we have the 4 base files.
+
+The properties, targets and tasks are all imported on all platforms and are conditioned per TFM.
+
+#### Targets in Blazor WebView
+
+The targets and props in the Blazor nugets are maintained by the Blazor team and they just have a single targets and props file for all platforms to share.
diff --git a/eng/Microsoft.Extensions.targets b/eng/Microsoft.Extensions.targets
index 931798a7942d..e1d2b8192c69 100644
--- a/eng/Microsoft.Extensions.targets
+++ b/eng/Microsoft.Extensions.targets
@@ -20,6 +20,26 @@
Update="System.Numerics.Vectors"
Version="$(SystemNumericsVectorsVersion)"
/>
+
+
+
+
+
+
+
+
https://github.com/dotnet/templating
3f4da9ced34942d83054e647f3b1d9d7dde281e8
-
+
https://github.com/dotnet/xharness
- bc9877ac24c13ef8d4ad4c2c3652291a1b02b78f
+ 6e20fd14ba45ff67193f961186d373ffbcfd5ea2
-
+
https://github.com/dotnet/xharness
- bc9877ac24c13ef8d4ad4c2c3652291a1b02b78f
+ 6e20fd14ba45ff67193f961186d373ffbcfd5ea2
-
+
https://github.com/dotnet/xharness
- bc9877ac24c13ef8d4ad4c2c3652291a1b02b78f
+ 6e20fd14ba45ff67193f961186d373ffbcfd5ea2
diff --git a/eng/Versions.props b/eng/Versions.props
index e4890550546e..39cc92db44f1 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -27,30 +27,38 @@
10.0.22621.755
1.0.4
- 7.0.2
- 7.0.2
- 7.0.2
- 7.0.2
+ 7.0.3
+ 7.0.3
+ 7.0.3
+ 7.0.3
7.0.1
7.0.1
7.0.1
- 7.0.2
- 7.0.2
+ 7.0.3
+ 7.0.3
7.0.1
- 7.0.2
+ 7.0.3
8.0.0-preview1.23067.2
3.3.3
3.3.3
4.5.0
- <_MicrosoftWebWebView2Version>1.0.1518.46
+ 4.5.5
+ 4.5.1
+ 7.0.1
+ 7.0.0
+ 7.0.0
+ 4.3.0
+ 4.3.0
+ 6.0.0
+ <_MicrosoftWebWebView2Version>1.0.1587.40
<_XamarinAndroidGlideVersion>4.13.2.2
<_XamarinAndroidXSecurityVersion>1.1.0-alpha03
<_XamarinGoogleCryptoTinkAndroidVersion>1.7.0.2
- 118.1.0
+ 118.1.0.1
+ maccatalyst-x64
diff --git a/src/Compatibility/Android.AppLinks/src/Compatibility.Android.AppLinks.csproj b/src/Compatibility/Android.AppLinks/src/Compatibility.Android.AppLinks.csproj
index c2235e2a14ce..b5a6215529bc 100644
--- a/src/Compatibility/Android.AppLinks/src/Compatibility.Android.AppLinks.csproj
+++ b/src/Compatibility/Android.AppLinks/src/Compatibility.Android.AppLinks.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Compatibility/ControlGallery/src/Android/Compatibility.ControlGallery.Android.csproj b/src/Compatibility/ControlGallery/src/Android/Compatibility.ControlGallery.Android.csproj
index d5e854e26c33..c98889dfa205 100644
--- a/src/Compatibility/ControlGallery/src/Android/Compatibility.ControlGallery.Android.csproj
+++ b/src/Compatibility/ControlGallery/src/Android/Compatibility.ControlGallery.Android.csproj
@@ -57,7 +57,6 @@
-
diff --git a/src/Compatibility/ControlGallery/src/Android/PlatformSpecificCoreGalleryFactory.cs b/src/Compatibility/ControlGallery/src/Android/PlatformSpecificCoreGalleryFactory.cs
index 280f6ffb863e..79c1d0761e39 100644
--- a/src/Compatibility/ControlGallery/src/Android/PlatformSpecificCoreGalleryFactory.cs
+++ b/src/Compatibility/ControlGallery/src/Android/PlatformSpecificCoreGalleryFactory.cs
@@ -16,11 +16,7 @@ public class PlatformSpecificCoreGalleryFactory : IPlatformSpecificCoreGalleryFa
public IEnumerable<(Func Create, string Title)> GetPages()
{
-#if HAVE_OPENTK
- yield return (() => new AdvancedOpenGLGallery(), "Advanced OpenGL Gallery - Legacy");
-#else
return null;
-#endif
}
}
}
diff --git a/src/Compatibility/ControlGallery/src/Core/ControlGalleryPages/FlowDirectionGallery.cs b/src/Compatibility/ControlGallery/src/Core/ControlGalleryPages/FlowDirectionGallery.cs
index 4bad11ecdf25..6e0700b4e331 100644
--- a/src/Compatibility/ControlGallery/src/Core/ControlGalleryPages/FlowDirectionGallery.cs
+++ b/src/Compatibility/ControlGallery/src/Core/ControlGalleryPages/FlowDirectionGallery.cs
@@ -291,8 +291,6 @@ void SetContent(FlowDirection direction)
lbl3.HorizontalTextAlignment = TextAlignment.Center;
lbl3.Text = "Center text";
- //var ogv = AddView(grid, ref col, ref row, hOptions, vOptions, margin);
-
var pkr = AddView(grid, ref col, ref row);
pkr.ItemsSource = Enumerable.Range(0, 10).ToList();
diff --git a/src/Compatibility/ControlGallery/src/Core/CoreGallery.cs b/src/Compatibility/ControlGallery/src/Core/CoreGallery.cs
index a8c0179a1ffd..e995bdd424f9 100644
--- a/src/Compatibility/ControlGallery/src/Core/CoreGallery.cs
+++ b/src/Compatibility/ControlGallery/src/Core/CoreGallery.cs
@@ -360,7 +360,6 @@ public override string ToString()
new GalleryPageFactory(() => new KeyboardCoreGallery(), "Keyboard Gallery"),
new GalleryPageFactory(() => new LabelCoreGalleryPage(), "Label Gallery"),
new GalleryPageFactory(() => new ListViewCoreGalleryPage(), "ListView Gallery"),
- new GalleryPageFactory(() => new OpenGLViewCoreGalleryPage(), "OpenGLView Gallery"),
new GalleryPageFactory(() => new PickerCoreGalleryPage(), "Picker Gallery"),
new GalleryPageFactory(() => new ProgressBarCoreGalleryPage(), "ProgressBar Gallery"),
new GalleryPageFactory(() => new MaterialProgressBarGallery(), "ProgressBar & Slider Gallery (Material)"),
@@ -422,10 +421,6 @@ public override string ToString()
new GalleryPageFactory(() => new MinimumSizeGallery(), "MinimumSize Gallery - Legacy"),
new GalleryPageFactory(() => new MultiGallery(), "Multi Gallery - Legacy"),
new GalleryPageFactory(() => new NavigationPropertiesGallery(), "Navigation Properties"),
-#if HAVE_OPENTK
- new GalleryPageFactory(() => new BasicOpenGLGallery(), "Basic OpenGL Gallery - Legacy"),
- new GalleryPageFactory(() => new AdvancedOpenGLGallery(), "Advanced OpenGL Gallery - Legacy"),
-#endif
new GalleryPageFactory(() => new PickerGallery(), "Picker Gallery - Legacy"),
new GalleryPageFactory(() => new ProgressBarGallery(), "ProgressBar Gallery - Legacy"),
new GalleryPageFactory(() => new RelativeLayoutGallery(), "RelativeLayout Gallery - Legacy"),
diff --git a/src/Compatibility/ControlGallery/src/Core/CoreGalleryPages/OpenGLViewCoreGalleryPage.cs b/src/Compatibility/ControlGallery/src/Core/CoreGalleryPages/OpenGLViewCoreGalleryPage.cs
deleted file mode 100644
index 207dede38931..000000000000
--- a/src/Compatibility/ControlGallery/src/Core/CoreGalleryPages/OpenGLViewCoreGalleryPage.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace Microsoft.Maui.Controls.Compatibility.ControlGallery
-{
- internal class OpenGLViewCoreGalleryPage : CoreGalleryPage
- {
- // TODO
- protected override bool SupportsFocus
- {
- get { return false; }
- }
-
- protected override void Build(StackLayout stackLayout)
- {
- base.Build(stackLayout);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Compatibility/ControlGallery/src/Core/GalleryPages/MemoryLeakGallery.cs b/src/Compatibility/ControlGallery/src/Core/GalleryPages/MemoryLeakGallery.cs
index b15d023ad019..e475f74a23af 100644
--- a/src/Compatibility/ControlGallery/src/Core/GalleryPages/MemoryLeakGallery.cs
+++ b/src/Compatibility/ControlGallery/src/Core/GalleryPages/MemoryLeakGallery.cs
@@ -97,7 +97,6 @@ public MemoryLeakGallery()
MakeButton(nameof(WebView), () => new WebView { BackgroundColor = Colors.Azure, HeightRequest = 50 }),
MakeButton(nameof(ProgressBar), () => new ProgressBar { BackgroundColor = Colors.Azure, Progress = 0.5 }),
MakeButton(nameof(Picker), () => new Picker { BackgroundColor = Colors.Azure, HeightRequest = 50 }),
- MakeButton(nameof(OpenGLView), () => new OpenGLView ()),
MakeButton(nameof(SearchBar), () => new SearchBar ()),
MakeButton(nameof(Slider), () => new Slider ()),
MakeButton(nameof(Stepper), () => new Stepper ()),
diff --git a/src/Compatibility/ControlGallery/src/Core/GalleryPages/OpenGLGalleries/AdvancedOpenGLGallery.cs b/src/Compatibility/ControlGallery/src/Core/GalleryPages/OpenGLGalleries/AdvancedOpenGLGallery.cs
deleted file mode 100644
index 5808f14377d1..000000000000
--- a/src/Compatibility/ControlGallery/src/Core/GalleryPages/OpenGLGalleries/AdvancedOpenGLGallery.cs
+++ /dev/null
@@ -1,218 +0,0 @@
-#if HAVE_OPENTK
-using System;
-using OpenTK;
-
-#if __WPF__ || __GTK__ || __MACOS__
-using OpenTK.Graphics.OpenGL;
-#elif __ANDROID__ || __IOS__
-using OpenTK.Graphics.ES20;
-#endif
-
-using Microsoft.Maui.Graphics;
-
-namespace Microsoft.Maui.Controls.Compatibility.ControlGallery
-{
- public class AdvancedOpenGLGallery : ContentPage
- {
- private const string VertexShader = @"
- uniform mat4 uMVPMatrix;
- attribute vec4 vColor;
- attribute vec4 vPosition;
- varying vec4 color;
- void main()
- {
- color = vColor;
- gl_Position = uMVPMatrix * vPosition;
- }";
-
- private const string FragmentShader = @"
- varying lowp vec4 color;
- void main (void)
- {
- gl_FragColor = color;
- }";
-
- private bool _initGl = false;
- private int _viewportWidth;
- private int _viewportHeight;
- private Vector4[] _vertices;
- private Vector4[] _colors;
-
- private uint _mProgramHandle;
- private int _mColorHandle;
- private int _mPositionHandle;
- private int _mMVPMatrixHandle;
- private Matrix4 _mProjectionMatrix;
- private Matrix4 _mViewMatrix;
- private Matrix4 _mModelViewProjectionMatrix;
-
- private Microsoft.Maui.Controls.OpenGLView _openGLView = null;
-
- public AdvancedOpenGLGallery()
- {
- Title = "Advanced OpenGLView Sample";
-
- var titleLabel = new Label
- {
- Text = "OpenGLView",
- FontSize = 36
- };
-
- _openGLView = new OpenGLView
- {
- HeightRequest = 300,
- WidthRequest = 300,
- HasRenderLoop = true
- };
-
- _openGLView.OnDisplay = r =>
- {
- if (!_initGl)
- {
- double width_in_pixels = 300;
- double height_in_pixels = 300;
-
- InitGl((int)width_in_pixels, (int)height_in_pixels);
- }
-
- Render();
- };
-
- var stack = new StackLayout
- {
- Padding = new Size(12, 12),
- Children = { titleLabel, _openGLView }
- };
-
- Content = stack;
- }
-
- void InitGl(int width, int height)
- {
- _viewportHeight = width;
- _viewportWidth = height;
-
- _vertices = new Vector4[]
- {
- new Vector4(0.0f, 0.5f, 0.0f, 1.0f),
- new Vector4(0.5f, -0.5f, 0.0f, 1.0f),
- new Vector4(-0.5f, -0.5f, 0.0f, 1.0f)
- };
-
- _colors = new Vector4[]
- {
- new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
- new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
- new Vector4(0.0f, 0.0f, 1.0f, 1.0f)
- };
-
- uint vertexShader = CompileShader(VertexShader, ShaderType.VertexShader);
- uint fragmentShader = CompileShader(FragmentShader, ShaderType.FragmentShader);
-
- _mProgramHandle = (uint)GL.CreateProgram();
- if (_mProgramHandle == 0)
- throw new InvalidOperationException("Unable to create program");
-
- GL.AttachShader(_mProgramHandle, vertexShader);
- GL.AttachShader(_mProgramHandle, fragmentShader);
-
- GL.BindAttribLocation(_mProgramHandle, 0, "vPosition");
- GL.LinkProgram(_mProgramHandle);
-
- GL.Viewport(0, 0, _viewportWidth, _viewportHeight);
-
- GL.UseProgram(_mProgramHandle);
-
- _initGl = true;
- }
-
- public static uint CompileShader(string shaderString, ShaderType shaderType)
- {
- uint shaderHandle = (uint)GL.CreateShader(shaderType);
- GL.ShaderSource((int)shaderHandle, shaderString);
- GL.CompileShader(shaderHandle);
-
- return shaderHandle;
- }
-
- public static void UniformMatrix4(int location, Matrix4 value)
- {
- GL.UniformMatrix4(location, 1, false, ref value.Row0.X);
- }
-
- void Render()
- {
- GL.UseProgram(_mProgramHandle);
-
- GL.ClearColor(0.7f, 0.7f, 0.7f, 1);
- GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
-
- float aspectRatio = ((float)Width) / ((float)Height);
- float ratio = ((float)_viewportWidth) / ((float)_viewportHeight);
-
- _mProjectionMatrix = Matrix4.CreateOrthographicOffCenter(-ratio, ratio, -1, 1, 0.1f, 10.0f);
-
- _mViewMatrix = Matrix4.LookAt(new Vector3(0, 0, 5), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
-
- _mModelViewProjectionMatrix = Matrix4.Mult(_mViewMatrix, _mProjectionMatrix);
-
- Matrix4 mModel = Matrix4.CreateRotationY((float)(Math.PI * 2.0 * ReferenceTime.GetTimeFromReferenceMs() / 5000.0));
-
- _mModelViewProjectionMatrix = Matrix4.Mult(_mModelViewProjectionMatrix, mModel);
-
- _mPositionHandle = GL.GetAttribLocation(_mProgramHandle, "vPosition");
-
- _mColorHandle = GL.GetAttribLocation(_mProgramHandle, "vColor");
-
- GL.EnableVertexAttribArray(_mPositionHandle);
- GL.EnableVertexAttribArray(_mColorHandle);
-
- unsafe
- {
- fixed (Vector4* pvertices = _vertices)
- {
- GL.VertexAttribPointer(_mPositionHandle, Vector4.SizeInBytes / 4, VertexAttribPointerType.Float, false, 0, new IntPtr(pvertices));
- }
-
- fixed (Vector4* pcolors = _colors)
- {
- GL.VertexAttribPointer(_mColorHandle, Vector4.SizeInBytes / 4, VertexAttribPointerType.Float, false, 0, new IntPtr(pcolors));
- }
- }
-
- _mMVPMatrixHandle = GL.GetUniformLocation(_mProgramHandle, "uMVPMatrix");
-
- UniformMatrix4(_mMVPMatrixHandle, _mModelViewProjectionMatrix);
-
-#pragma warning disable 0618
- GL.DrawArrays(BeginMode.Triangles, 0, 3);
-#pragma warning restore 0618
- GL.Finish();
- GL.DisableVertexAttribArray(_mPositionHandle);
- GL.DisableVertexAttribArray(_mColorHandle);
- }
- }
-
- public class ReferenceTime
- {
- private static DateTime reference_time;
- private static bool reference_time_set = false;
-
- public static double GetTimeFromReferenceMs()
- {
- if (!reference_time_set)
- {
- reference_time = DateTime.Now;
- reference_time_set = true;
-
- return 0.0;
- }
-
- DateTime actual_time = DateTime.Now;
- TimeSpan ts = new TimeSpan(actual_time.Ticks - reference_time.Ticks);
-
- return ts.TotalMilliseconds;
- }
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/Compatibility/ControlGallery/src/Core/GalleryPages/OpenGLGalleries/BasicOpenGLGallery.cs b/src/Compatibility/ControlGallery/src/Core/GalleryPages/OpenGLGalleries/BasicOpenGLGallery.cs
deleted file mode 100644
index a8f792787af1..000000000000
--- a/src/Compatibility/ControlGallery/src/Core/GalleryPages/OpenGLGalleries/BasicOpenGLGallery.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-#if HAVE_OPENTK
-using System;
-using OpenTK.Graphics.OpenGL;
-
-namespace Microsoft.Maui.Controls.Compatibility.ControlGallery
-{
- public class BasicOpenGLGallery : ContentPage
- {
- private bool _initGl = false;
- private int _viewportWidth;
- private int _viewportHeight;
- private uint _mProgramHandle;
- private OpenGLView _openGLView = null;
-
- public BasicOpenGLGallery()
- {
- Title = "Basic OpenGLView Sample";
-
- var titleLabel = new Label
- {
- Text = "OpenGLView",
- FontSize = 36
- };
-
- _openGLView = new OpenGLView
- {
- HeightRequest = 300,
- WidthRequest = 300,
- HasRenderLoop = true
- };
-
- _openGLView.OnDisplay = r =>
- {
- if (!_initGl)
- {
- double width_in_pixels = 300;
- double height_in_pixels = 300;
-
- InitGl((int)width_in_pixels, (int)height_in_pixels);
- }
-
- Render();
- };
-
- var stack = new StackLayout
- {
- Padding = new Size(12, 12),
- Children = { titleLabel, _openGLView }
- };
-
- Content = stack;
- }
-
- void InitGl(int width, int height)
- {
- _viewportHeight = width;
- _viewportWidth = height;
-
- _mProgramHandle = (uint)GL.CreateProgram();
- if (_mProgramHandle == 0)
- throw new InvalidOperationException("Unable to create program");
-
- GL.BindAttribLocation(_mProgramHandle, 0, "vPosition");
- GL.LinkProgram(_mProgramHandle);
-
- GL.Viewport(0, 0, _viewportWidth, _viewportHeight);
-
- GL.UseProgram(_mProgramHandle);
-
- _initGl = true;
- }
-
-
- void Render()
- {
-#pragma warning disable 0618
- GL.ClearColor(0, 0, 0, 0);
- GL.Clear(ClearBufferMask.ColorBufferBit);
-
- GL.Color3(1.0f, 0.85f, 0.35f);
- GL.Begin(BeginMode.Triangles);
-
- GL.Vertex3(0.0, 0.6, 0.0);
- GL.Vertex3(-0.2, -0.3, 0.0);
- GL.Vertex3(0.2, -0.3, 0.0);
-#pragma warning restore 0618
-
- GL.End();
-
- GL.Flush();
- }
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/Compatibility/ControlGallery/src/Issues.Shared/Helpers/ViewHelper.cs b/src/Compatibility/ControlGallery/src/Issues.Shared/Helpers/ViewHelper.cs
index f79a9ba4c49a..924bacd9ea7d 100644
--- a/src/Compatibility/ControlGallery/src/Issues.Shared/Helpers/ViewHelper.cs
+++ b/src/Compatibility/ControlGallery/src/Issues.Shared/Helpers/ViewHelper.cs
@@ -24,7 +24,6 @@ public static List GetAllViews()
new ListView { ItemsSource = Enumerable.Range(0,10), ItemTemplate = new DataTemplate(typeof(ImageCell)) },
new ListView { ItemsSource = Enumerable.Range(0,10), ItemTemplate = new DataTemplate(typeof(EntryCell)) },
new ListView { ItemsSource = Enumerable.Range(0,10), ItemTemplate = new DataTemplate(typeof(SwitchCell)) },
- new OpenGLView { },
new Picker { },
new ProgressBar { },
new SearchBar { },
diff --git a/src/Compatibility/ControlGallery/src/Issues.Shared/Issue8958.xaml.cs b/src/Compatibility/ControlGallery/src/Issues.Shared/Issue8958.xaml.cs
index c49926c06f19..a2cd08fa0b16 100644
--- a/src/Compatibility/ControlGallery/src/Issues.Shared/Issue8958.xaml.cs
+++ b/src/Compatibility/ControlGallery/src/Issues.Shared/Issue8958.xaml.cs
@@ -49,7 +49,9 @@ protected override void Init()
}
[Preserve(AllMembers = true)]
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct Issue8958Model
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public string Title { get; set; }
}
diff --git a/src/Compatibility/ControlGallery/src/Issues.Shared/TransparentOverlayTests.cs b/src/Compatibility/ControlGallery/src/Issues.Shared/TransparentOverlayTests.cs
index 11b5c5639386..1c63c511be31 100644
--- a/src/Compatibility/ControlGallery/src/Issues.Shared/TransparentOverlayTests.cs
+++ b/src/Compatibility/ControlGallery/src/Issues.Shared/TransparentOverlayTests.cs
@@ -65,7 +65,9 @@ Button MenuButton(TestPoint test)
}
[Preserve(AllMembers = true)]
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct TestPoint
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public TestPoint(int i) : this()
{
diff --git a/src/Compatibility/ControlGallery/src/Tizen/RegistrarValidationService.cs b/src/Compatibility/ControlGallery/src/Tizen/RegistrarValidationService.cs
index 1d029d5eec05..433c9b62f2c7 100644
--- a/src/Compatibility/ControlGallery/src/Tizen/RegistrarValidationService.cs
+++ b/src/Compatibility/ControlGallery/src/Tizen/RegistrarValidationService.cs
@@ -13,7 +13,7 @@ public bool Validate(VisualElement element, out string message)
{
message = "Success";
- if (element == null || element is OpenGLView)
+ if (element == null)
return true;
var renderer = Platform.Tizen.Platform.GetOrCreateRenderer(element);
diff --git a/src/Compatibility/ControlGallery/src/UITests.Shared/PlatformQueries.cs b/src/Compatibility/ControlGallery/src/UITests.Shared/PlatformQueries.cs
index e2ec706546eb..ad4493df7216 100644
--- a/src/Compatibility/ControlGallery/src/UITests.Shared/PlatformQueries.cs
+++ b/src/Compatibility/ControlGallery/src/UITests.Shared/PlatformQueries.cs
@@ -72,7 +72,6 @@ internal static class PlatformViews
public static readonly string Label = "UILabel";
public static readonly string ListView = "UITableView";
public static readonly string Map = "MKMapView";
- public static readonly string OpenGLView = "GLKView";
public static readonly string Picker = "UITextField";
public static readonly string Pin = "MKPinAnnotationView";
public static readonly string ProgressBar = "UIProgressView";
@@ -98,7 +97,6 @@ internal static class PlatformViews
public static readonly string Label = "android.widget.TextView";
public static readonly string ListView = "android.widget.ListView";
public static readonly string Map = "android.gms.maps.GoogleMap";
- public static readonly string OpenGLView = "android.widget.GLSurfaceView";
public static readonly string Picker = "android.widget.EditText";
public static readonly string Pin = "android.gms.maps.model.Marker";
public static readonly string ProgressBar = "android.widget.ProgressBar";
diff --git a/src/Compatibility/ControlGallery/src/UITests.Shared/Queries.cs b/src/Compatibility/ControlGallery/src/UITests.Shared/Queries.cs
index 5d488eb216ac..a9c24c9cefda 100644
--- a/src/Compatibility/ControlGallery/src/UITests.Shared/Queries.cs
+++ b/src/Compatibility/ControlGallery/src/UITests.Shared/Queries.cs
@@ -30,7 +30,6 @@ internal static class GalleryQueries
public const string ImageButtonGallery = "* marked:'Image Button Gallery'";
public const string LabelGallery = "* marked:'Label Gallery'";
public const string ListViewGallery = "* marked:'ListView Gallery'";
- public const string OpenGLViewGallery = "* marked:'OpenGLView Gallery'";
public const string PickerGallery = "* marked:'Picker Gallery'";
public const string ProgressBarGallery = "* marked:'ProgressBar Gallery'";
public const string RadioButtonGallery = "* marked:'RadioButton Core Gallery'";
@@ -94,7 +93,6 @@ internal static class Views
public static readonly string Label = PlatformViews.Label;
public static readonly string ListView = PlatformViews.ListView;
public static readonly string Map = PlatformViews.Map;
- public static readonly string OpenGLView = PlatformViews.OpenGLView;
public static readonly string Picker = PlatformViews.Picker;
public static readonly string Pin = PlatformViews.Pin;
public static readonly string ProgressBar = PlatformViews.ProgressBar;
diff --git a/src/Compatibility/ControlGallery/src/WinUI/RegistrarValidationService.cs b/src/Compatibility/ControlGallery/src/WinUI/RegistrarValidationService.cs
index ddd9a940d6e7..2f0620811662 100644
--- a/src/Compatibility/ControlGallery/src/WinUI/RegistrarValidationService.cs
+++ b/src/Compatibility/ControlGallery/src/WinUI/RegistrarValidationService.cs
@@ -13,7 +13,7 @@ public bool Validate(VisualElement element, out string message)
{
message = "Success";
- if (element == null || element is OpenGLView)
+ if (element == null)
return true;
#pragma warning disable CS0612 // Type or member is obsolete
diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/PlatformSpecificCoreGalleryFactory.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/PlatformSpecificCoreGalleryFactory.cs
index 818aae56820c..8ce8f4fbab86 100644
--- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/PlatformSpecificCoreGalleryFactory.cs
+++ b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/PlatformSpecificCoreGalleryFactory.cs
@@ -14,12 +14,7 @@ public class PlatformSpecificCoreGalleryFactory : IPlatformSpecificCoreGalleryFa
public IEnumerable<(Func Create, string Title)> GetPages()
{
-#if HAVE_OPENTK
- yield return (() => new BasicOpenGLGallery(), "Basic OpenGL Gallery - Legacy");
- yield return (() => new AdvancedOpenGLGallery(), "Advanced OpenGL Gallery - Legacy");
-#else
return null;
-#endif
}
}
}
diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/Xamarin.Forms.ControlGallery.GTK.csproj b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/Xamarin.Forms.ControlGallery.GTK.csproj
index 212b639a303f..3e68e6b06902 100644
--- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/Xamarin.Forms.ControlGallery.GTK.csproj
+++ b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.GTK/Xamarin.Forms.ControlGallery.GTK.csproj
@@ -89,12 +89,6 @@
-
- GalleryPages\AdvancedOpenGLGallery.cs
-
-
- GalleryPages\BasicOpenGLGallery.cs
-
diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/PlatformSpecificCoreGalleryFactory.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/PlatformSpecificCoreGalleryFactory.cs
index a1b39e9d59fb..0bfe0e7996c1 100644
--- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/PlatformSpecificCoreGalleryFactory.cs
+++ b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/PlatformSpecificCoreGalleryFactory.cs
@@ -14,12 +14,7 @@ public class PlatformSpecificCoreGalleryFactory : IPlatformSpecificCoreGalleryFa
public IEnumerable<(Func Create, string Title)> GetPages()
{
-#if HAVE_OPENTK
- yield return (() => new BasicOpenGLGallery(), "Basic OpenGL Gallery - Legacy");
- yield return (() => new AdvancedOpenGLGallery(), "Advanced OpenGL Gallery - Legacy");
-#else
return null;
-#endif
}
}
}
diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/Xamarin.Forms.ControlGallery.MacOS.csproj b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/Xamarin.Forms.ControlGallery.MacOS.csproj
index ab0ffbc09e6d..5c7589714645 100644
--- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/Xamarin.Forms.ControlGallery.MacOS.csproj
+++ b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.MacOS/Xamarin.Forms.ControlGallery.MacOS.csproj
@@ -104,12 +104,6 @@
-
- GalleryPages\AdvancedOpenGLGallery.cs
-
-
- GalleryPages\BasicOpenGLGallery.cs
-
diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/PlatformSpecificCoreGalleryFactory.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/PlatformSpecificCoreGalleryFactory.cs
index 333acc2bd177..e900eb93a927 100644
--- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/PlatformSpecificCoreGalleryFactory.cs
+++ b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/PlatformSpecificCoreGalleryFactory.cs
@@ -14,12 +14,7 @@ public class PlatformSpecificCoreGalleryFactory : IPlatformSpecificCoreGalleryFa
public IEnumerable<(Func Create, string Title)> GetPages()
{
-#if HAVE_OPENTK
- yield return (() => new BasicOpenGLGallery(), "Basic OpenGL Gallery - Legacy");
- yield return (() => new AdvancedOpenGLGallery(), "Advanced OpenGL Gallery - Legacy");
-#else
return null;
-#endif
}
}
}
diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/RegistrarValidationService.cs b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/RegistrarValidationService.cs
index 464164719077..e976feb673a1 100644
--- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/RegistrarValidationService.cs
+++ b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/RegistrarValidationService.cs
@@ -12,7 +12,7 @@ public bool Validate(VisualElement element, out string message)
{
message = "Success";
- if (element == null || element is OpenGLView)
+ if (element == null)
return true;
var renderer = Platform.WPF.Platform.GetOrCreateRenderer(element);
diff --git a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/Xamarin.Forms.ControlGallery.WPF.csproj b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/Xamarin.Forms.ControlGallery.WPF.csproj
index e88efd4e20a9..df3b2c2cc2e5 100644
--- a/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/Xamarin.Forms.ControlGallery.WPF.csproj
+++ b/src/Compatibility/ControlGallery/src/Xamarin.Forms.ControlGallery.WPF/Xamarin.Forms.ControlGallery.WPF.csproj
@@ -42,12 +42,6 @@
-
- GalleryPages\AdvancedOpenGLGallery.cs
-
-
- GalleryPages\BasicOpenGLGallery.cs
-
diff --git a/src/Compatibility/ControlGallery/src/iOS/Compatibility.ControlGallery.iOS.csproj b/src/Compatibility/ControlGallery/src/iOS/Compatibility.ControlGallery.iOS.csproj
index 9596c55b7a69..3c73eca148a5 100644
--- a/src/Compatibility/ControlGallery/src/iOS/Compatibility.ControlGallery.iOS.csproj
+++ b/src/Compatibility/ControlGallery/src/iOS/Compatibility.ControlGallery.iOS.csproj
@@ -35,10 +35,6 @@
-
-
-
-
diff --git a/src/Compatibility/ControlGallery/src/iOS/PlatformSpecificCoreGalleryFactory.cs b/src/Compatibility/ControlGallery/src/iOS/PlatformSpecificCoreGalleryFactory.cs
index a0fc10b98716..ac5ffc8f5167 100644
--- a/src/Compatibility/ControlGallery/src/iOS/PlatformSpecificCoreGalleryFactory.cs
+++ b/src/Compatibility/ControlGallery/src/iOS/PlatformSpecificCoreGalleryFactory.cs
@@ -16,11 +16,7 @@ public class PlatformSpecificCoreGalleryFactory : IPlatformSpecificCoreGalleryFa
public IEnumerable<(Func Create, string Title)> GetPages()
{
-#if HAVE_OPENTK
- yield return (() => new AdvancedOpenGLGallery(), "Advanced OpenGL Gallery - Legacy");
-#else
return null;
-#endif
}
}
}
diff --git a/src/Compatibility/Core/src/Android/AppCompat/FlyoutPageContainer.cs b/src/Compatibility/Core/src/Android/AppCompat/FlyoutPageContainer.cs
index 3f78667948e4..d1ae9d6c44e0 100644
--- a/src/Compatibility/Core/src/Android/AppCompat/FlyoutPageContainer.cs
+++ b/src/Compatibility/Core/src/Android/AppCompat/FlyoutPageContainer.cs
@@ -222,7 +222,7 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- if (_currentFragment != null && !FragmentManager.IsDestroyed)
+ if (_currentFragment != null && !FragmentManager.IsDestroyed(Context))
{
FragmentTransaction transaction = FragmentManager.BeginTransactionEx();
transaction.RemoveEx(_currentFragment);
diff --git a/src/Compatibility/Core/src/Android/AppCompat/FormsAppCompatActivity.cs b/src/Compatibility/Core/src/Android/AppCompat/FormsAppCompatActivity.cs
index 5cdce59371da..7a433c74536b 100644
--- a/src/Compatibility/Core/src/Android/AppCompat/FormsAppCompatActivity.cs
+++ b/src/Compatibility/Core/src/Android/AppCompat/FormsAppCompatActivity.cs
@@ -26,7 +26,9 @@ public enum ActivationFlags : long
DisableSetStatusBarColor = 1 << 0,
}
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct ActivationOptions
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public ActivationOptions(Bundle bundle)
{
diff --git a/src/Compatibility/Core/src/Android/AppCompat/FormsFragmentPagerAdapter.cs b/src/Compatibility/Core/src/Android/AppCompat/FormsFragmentPagerAdapter.cs
index 965aaed98ef5..992b18c70a8c 100644
--- a/src/Compatibility/Core/src/Android/AppCompat/FormsFragmentPagerAdapter.cs
+++ b/src/Compatibility/Core/src/Android/AppCompat/FormsFragmentPagerAdapter.cs
@@ -84,7 +84,7 @@ protected override void Dispose(bool disposing)
_page = null;
- if (!_fragmentManager.IsDestroyed)
+ if (!_fragmentManager.IsDestroyed(_page?.Handler?.MauiContext?.Context))
{
FragmentTransaction transaction = _fragmentManager.BeginTransactionEx();
diff --git a/src/Compatibility/Core/src/Android/FastRenderers/AutomationPropertiesProvider.cs b/src/Compatibility/Core/src/Android/FastRenderers/AutomationPropertiesProvider.cs
index c3a0c2c5f05a..d5db18c31acb 100644
--- a/src/Compatibility/Core/src/Android/FastRenderers/AutomationPropertiesProvider.cs
+++ b/src/Compatibility/Core/src/Android/FastRenderers/AutomationPropertiesProvider.cs
@@ -92,6 +92,7 @@ void OnElementChanged(object sender, VisualElementChangedEventArgs e)
void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
+#pragma warning disable CS0618 // Type or member is obsolete
if (e.PropertyName == AutomationProperties.HelpTextProperty.PropertyName)
{
SetContentDescription();
@@ -108,6 +109,7 @@ void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
SetLabeledBy();
}
+#pragma warning restore CS0618 // Type or member is obsolete
}
}
}
diff --git a/src/Compatibility/Core/src/Android/Forms.cs b/src/Compatibility/Core/src/Android/Forms.cs
index 1d9e8ad73840..22821331f35f 100644
--- a/src/Compatibility/Core/src/Android/Forms.cs
+++ b/src/Compatibility/Core/src/Android/Forms.cs
@@ -29,9 +29,11 @@
namespace Microsoft.Maui.Controls.Compatibility
{
[Obsolete]
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct InitializationOptions
{
public struct EffectScope
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public string Name;
public ExportEffectAttribute[] Effects;
diff --git a/src/Compatibility/Core/src/Android/Renderers/OpenGLViewRenderer.cs b/src/Compatibility/Core/src/Android/Renderers/OpenGLViewRenderer.cs
deleted file mode 100644
index 9ce5f95d6743..000000000000
--- a/src/Compatibility/Core/src/Android/Renderers/OpenGLViewRenderer.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-using System;
-using System.ComponentModel;
-using Android.Content;
-using Android.Opengl;
-using Javax.Microedition.Khronos.Opengles;
-using Microsoft.Maui.Controls.Platform;
-using Microsoft.Maui.Graphics;
-using EGLConfig = Javax.Microedition.Khronos.Egl.EGLConfig;
-using Object = Java.Lang.Object;
-
-namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
-{
- [Obsolete]
- internal class OpenGLViewRenderer : ViewRenderer
- {
- bool _disposed;
-
- public OpenGLViewRenderer(Context context) : base(context)
- {
- AutoPackage = false;
- }
-
- protected override void Dispose(bool disposing)
- {
- if (!_disposed && disposing)
- {
- _disposed = true;
-
- if (Element != null)
- ((IOpenGlViewController)Element).DisplayRequested -= Render;
- }
- base.Dispose(disposing);
- }
-
- protected override GLSurfaceView CreateNativeControl()
- {
- return new GLSurfaceView(Context);
- }
-
- protected override void OnElementChanged(ElementChangedEventArgs e)
- {
- base.OnElementChanged(e);
-
- if (e.OldElement != null)
- ((IOpenGlViewController)Element).DisplayRequested -= Render;
-
- if (e.NewElement != null)
- {
- GLSurfaceView surfaceView = Control;
- if (surfaceView == null)
- {
- surfaceView = CreateNativeControl();
- surfaceView.SetEGLContextClientVersion(2);
- SetNativeControl(surfaceView);
- }
-
- ((IOpenGlViewController)Element).DisplayRequested += Render;
- surfaceView.SetRenderer(new Renderer(Element));
- SetRenderMode();
- }
- }
-
- protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- base.OnElementPropertyChanged(sender, e);
-
- if (e.PropertyName == OpenGLView.HasRenderLoopProperty.PropertyName)
- SetRenderMode();
- }
-
- void Render(object sender, EventArgs eventArgs)
- {
- if (Element.HasRenderLoop)
- return;
- Control.RequestRender();
- }
-
- void SetRenderMode()
- {
- Control.RenderMode = Element.HasRenderLoop ? Rendermode.Continuously : Rendermode.WhenDirty;
- }
-
- class Renderer : Object, GLSurfaceView.IRenderer
- {
- readonly OpenGLView _model;
- Rect _rect;
-
- public Renderer(OpenGLView model)
- {
- _model = model;
- }
-
- public void OnDrawFrame(IGL10 gl)
- {
- Action onDisplay = _model.OnDisplay;
- if (onDisplay == null)
- return;
- onDisplay(_rect);
- }
-
- public void OnSurfaceChanged(IGL10 gl, int width, int height)
- {
- _rect = new Rect(0.0, 0.0, width, height);
- }
-
- public void OnSurfaceCreated(IGL10 gl, EGLConfig config)
- {
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Compatibility/Core/src/Android/VisualElementRenderer.cs b/src/Compatibility/Core/src/Android/VisualElementRenderer.cs
index ed5fa9bfb339..335af78c9828 100644
--- a/src/Compatibility/Core/src/Android/VisualElementRenderer.cs
+++ b/src/Compatibility/Core/src/Android/VisualElementRenderer.cs
@@ -300,10 +300,10 @@ protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEv
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
- if (Element == null)
- return;
-
- UpdateLayout(((IElementController)Element).LogicalChildren);
+ if (Element is IElementController controller)
+ {
+ UpdateLayout(controller.LogicalChildren);
+ }
}
public override void Draw(Canvas canvas)
diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs
index 16733fe69a85..f1ea9722b4c4 100644
--- a/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs
+++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.Tizen.cs
@@ -1,7 +1,7 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Maui.Controls.Compatibility;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.LifecycleEvents;
-using Microsoft.Maui.Controls.Compatibility;
-using Microsoft.Extensions.DependencyInjection;
using TDeviceInfo = Tizen.UIExtensions.Common.DeviceInfo;
namespace Microsoft.Maui.Controls.Compatibility.Hosting
diff --git a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs
index 0604c85e3165..a425c83983b6 100644
--- a/src/Compatibility/Core/src/AppHostBuilderExtensions.cs
+++ b/src/Compatibility/Core/src/AppHostBuilderExtensions.cs
@@ -36,7 +36,6 @@
#elif TIZEN
using Microsoft.Maui.Controls.Compatibility.Platform.Tizen;
using Microsoft.Maui.Graphics.Skia;
-using OpenGLViewRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer;
using StreamImagesourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.StreamImageSourceHandler;
using ImageLoaderSourceHandler = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.UriImageSourceHandler;
using DefaultRenderer = Microsoft.Maui.Controls.Compatibility.Platform.Tizen.DefaultRenderer;
@@ -77,11 +76,6 @@ public static MauiAppBuilder UseMauiCompatibility(this MauiAppBuilder builder)
#if !WINDOWS
#if !(MACCATALYST || MACOS)
-#pragma warning disable CS0618 // Type or member is obsolete
-#pragma warning disable CS0612 // Type or member is obsolete
- handlers.TryAddCompatibilityRenderer(typeof(OpenGLView), typeof(OpenGLViewRenderer));
-#pragma warning restore CS0612 // Type or member is obsolete
-#pragma warning restore CS0618 // Type or member is obsolete
#endif
#else
#pragma warning disable CS0618 // Type or member is obsolete
diff --git a/src/Compatibility/Core/src/Compatibility.csproj b/src/Compatibility/Core/src/Compatibility.csproj
index 1bed9d1a8ea9..b3b37f710696 100644
--- a/src/Compatibility/Core/src/Compatibility.csproj
+++ b/src/Compatibility/Core/src/Compatibility.csproj
@@ -8,7 +8,7 @@
iOS\
Windows\
Tizen\
- false
+ true
true
true
true
@@ -20,7 +20,7 @@
$(DefineConstants);WINDOWS
-
+
@@ -57,4 +57,6 @@
+
+
diff --git a/src/Compatibility/Core/src/GTK/Compatibility.GTK.csproj b/src/Compatibility/Core/src/GTK/Compatibility.GTK.csproj
index 4175f802f74d..91693d8ab489 100644
--- a/src/Compatibility/Core/src/GTK/Compatibility.GTK.csproj
+++ b/src/Compatibility/Core/src/GTK/Compatibility.GTK.csproj
@@ -129,7 +129,6 @@
-
@@ -197,7 +196,6 @@
-
diff --git a/src/Compatibility/Core/src/GTK/Controls/OpenGLView.cs b/src/Compatibility/Core/src/GTK/Controls/OpenGLView.cs
deleted file mode 100644
index ae39a222d3ca..000000000000
--- a/src/Compatibility/Core/src/GTK/Controls/OpenGLView.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using Gtk;
-using OpenTK.GLWidget;
-using OpenTK.Graphics;
-
-namespace Microsoft.Maui.Controls.Compatibility.Platform.GTK.Controls
-{
- public class OpenGLView : EventBox
- {
- private GLWidget _glWidget;
-
- private Action _action;
- private bool _hasLoop;
- protected uint _timerId;
-
- public OpenGLView()
- {
- if (!GtkOpenGL.IsInitialized)
- throw new InvalidOperationException("call GtkOpenGL.Init() before use OpenGLView");
-
- GraphicsMode graphicsMode = GraphicsMode.Default;
-
- _glWidget = new GLWidget(GraphicsMode.Default);
-
- _glWidget.SingleBuffer = true;
- _glWidget.ColorBPP = graphicsMode.ColorFormat.BitsPerPixel;
- _glWidget.AccumulatorBPP = graphicsMode.AccumulatorFormat.BitsPerPixel;
- _glWidget.DepthBPP = graphicsMode.Depth;
- _glWidget.Samples = graphicsMode.Samples;
- _glWidget.StencilBPP = graphicsMode.Stencil;
- _glWidget.Stereo = graphicsMode.Stereo;
- _glWidget.GlVersionMajor = 2;
- _glWidget.GlVersionMinor = 1;
- _glWidget.CanFocus = true;
- _glWidget.GraphicsContextFlags = GraphicsContextFlags.Default;
-
- _glWidget.Initialized += new EventHandler(OnGLWidgetInitialized);
- _glWidget.RenderFrame += new EventHandler(OnGLWidgetRenderer);
- _glWidget.Destroyed += new EventHandler(OnGLWidgetDestroy);
-
- _glWidget.AddEvents((int)Gdk.EventMask.AllEventsMask);
-
- Add(_glWidget);
-
- _glWidget.ShowAll();
- }
-
- public Action OnDisplay
- {
- get { return _action; }
- set { _action = value; }
- }
-
- public bool HasRenderLoop
- {
- get { return _hasLoop; }
- set { _hasLoop = value; }
- }
-
- protected void OnGLWidgetInitialized(object sender, EventArgs e)
- {
- _timerId = GLib.Timeout.Add(16, new GLib.TimeoutHandler(Render));
- }
-
- protected void OnGLWidgetRenderer(object sender, EventArgs e)
- {
- _timerId = GLib.Timeout.Add(16, new GLib.TimeoutHandler(Render));
- }
-
- protected void OnGLWidgetDestroy(object sender, EventArgs e)
- {
- GLib.Source.Remove(_timerId);
- }
-
- public override void Destroy()
- {
- base.Destroy();
-
- if (_glWidget != null)
- {
- _glWidget.Destroy();
- }
- }
-
- private bool Render()
- {
- if (!HasRenderLoop)
- {
- return false;
- }
- else
- {
- OnDisplay(new Rectangle(0, 0, WidthRequest, HeightRequest));
-
- return true;
- }
- }
- }
-}
diff --git a/src/Compatibility/Core/src/GTK/Properties/AssemblyInfo.cs b/src/Compatibility/Core/src/GTK/Properties/AssemblyInfo.cs
index a6aeaa384cb1..98b31b3afbee 100644
--- a/src/Compatibility/Core/src/GTK/Properties/AssemblyInfo.cs
+++ b/src/Compatibility/Core/src/GTK/Properties/AssemblyInfo.cs
@@ -28,7 +28,6 @@
#pragma warning restore CS0618 // Type or member is obsolete
[assembly: ExportRenderer(typeof(FlyoutPage), typeof(FlyoutPageRenderer))]
[assembly: ExportRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer))]
-[assembly: ExportRenderer(typeof(OpenGLView), typeof(OpenGLViewRenderer))]
[assembly: ExportRenderer(typeof(Page), typeof(PageRenderer))]
[assembly: ExportRenderer(typeof(Picker), typeof(PickerRenderer))]
[assembly: ExportRenderer(typeof(ProgressBar), typeof(ProgressBarRenderer))]
diff --git a/src/Compatibility/Core/src/GTK/Renderers/OpenGLViewRenderer.cs b/src/Compatibility/Core/src/GTK/Renderers/OpenGLViewRenderer.cs
deleted file mode 100644
index ba030bbaa6bc..000000000000
--- a/src/Compatibility/Core/src/GTK/Renderers/OpenGLViewRenderer.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using System;
-using System.ComponentModel;
-
-namespace Microsoft.Maui.Controls.Compatibility.Platform.GTK.Renderers
-{
- public class OpenGLViewRenderer : ViewRenderer
- {
- private Controls.OpenGLView _openGlView;
- private bool _disposed;
-
- protected override void Dispose(bool disposing)
- {
- if (!_disposed && disposing)
- {
- _disposed = true;
-
- if (Element != null)
- ((IOpenGlViewController)Element).DisplayRequested -= OnDisplay;
- }
-
- base.Dispose(disposing);
- }
-
- protected override void OnElementChanged(ElementChangedEventArgs e)
- {
- if (e.OldElement != null)
- ((IOpenGlViewController)e.OldElement).DisplayRequested -= OnDisplay;
-
- if (e.NewElement != null)
- {
- // The Open Toolkit library is a low-level C# binding for OpenGL, OpenGL ES and OpenAL.
- // Runs on Linux, macOS and Windows with GTK# (and more platforms).
- _openGlView = new Controls.OpenGLView();
- SetNativeControl(_openGlView);
-
- ((IOpenGlViewController)e.NewElement).DisplayRequested += OnDisplay;
-
- SetRenderMode();
- SetupRenderAction();
- }
-
- base.OnElementChanged(e);
- }
-
- protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- base.OnElementPropertyChanged(sender, e);
-
- if (e.PropertyName == OpenGLView.HasRenderLoopProperty.PropertyName)
- {
- SetRenderMode();
- SetupRenderAction();
- }
- }
-
- public void OnDisplay(object sender, EventArgs eventArgs)
- {
- if (Element.HasRenderLoop)
- return;
-
- SetupRenderAction();
- }
-
- private void SetRenderMode()
- {
- Control.HasRenderLoop = Element.HasRenderLoop;
- }
-
- private void SetupRenderAction()
- {
- if (!Element.HasRenderLoop)
- return;
-
- var model = Element;
- var onDisplay = model.OnDisplay;
-
- if (_openGlView != null)
- {
- _openGlView.OnDisplay = onDisplay;
- }
- }
- }
-}
diff --git a/src/Compatibility/Core/src/MacOS/Compatibility.macOS.csproj b/src/Compatibility/Core/src/MacOS/Compatibility.macOS.csproj
index 002a434d93a1..458ca5871531 100644
--- a/src/Compatibility/Core/src/MacOS/Compatibility.macOS.csproj
+++ b/src/Compatibility/Core/src/MacOS/Compatibility.macOS.csproj
@@ -131,8 +131,6 @@
-
-
diff --git a/src/Compatibility/Core/src/MacOS/Controls/MacOSOpenGLView.cs b/src/Compatibility/Core/src/MacOS/Controls/MacOSOpenGLView.cs
deleted file mode 100644
index 47634acd5cd0..000000000000
--- a/src/Compatibility/Core/src/MacOS/Controls/MacOSOpenGLView.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using AppKit;
-
-namespace Microsoft.Maui.Controls.Compatibility.Platform.MacOS
-{
- //TODO: Still not implemented on macOS
- public class MacOSOpenGLView : NSView
- {
- public MacOSOpenGLView()
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/Compatibility/Core/src/MacOS/Properties/AssemblyInfo.cs b/src/Compatibility/Core/src/MacOS/Properties/AssemblyInfo.cs
index e842345ef5de..300b18a9f65e 100644
--- a/src/Compatibility/Core/src/MacOS/Properties/AssemblyInfo.cs
+++ b/src/Compatibility/Core/src/MacOS/Properties/AssemblyInfo.cs
@@ -33,7 +33,6 @@
[assembly: ExportRenderer(typeof(Entry), typeof(EntryRenderer))]
[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
[assembly: ExportRenderer(typeof(Image), typeof(ImageRenderer))]
-[assembly: ExportRenderer(typeof(OpenGLView), typeof(OpenGLViewRenderer))]
[assembly: ExportRenderer(typeof(Picker), typeof(PickerRenderer))]
[assembly: ExportRenderer(typeof(ProgressBar), typeof(ProgressBarRenderer))]
[assembly: ExportRenderer(typeof(SearchBar), typeof(SearchBarRenderer))]
diff --git a/src/Compatibility/Core/src/MacOS/Renderers/OpenGLViewRenderer.cs b/src/Compatibility/Core/src/MacOS/Renderers/OpenGLViewRenderer.cs
deleted file mode 100644
index 86a7458f4945..000000000000
--- a/src/Compatibility/Core/src/MacOS/Renderers/OpenGLViewRenderer.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using System;
-using System.ComponentModel;
-using CoreVideo;
-
-namespace Microsoft.Maui.Controls.Compatibility.Platform.MacOS
-{
- // ReSharper disable once InconsistentNaming
- internal class OpenGLViewRenderer : ViewRenderer
- {
- CVDisplayLink _displayLink;
-
- public void Display(object sender, EventArgs eventArgs)
- {
- if (Element.HasRenderLoop)
- return;
- SetupRenderLoop(true);
- }
-
- protected override void Dispose(bool disposing)
- {
- if (_displayLink != null)
- {
- _displayLink.Dispose();
- _displayLink = null;
-
- if (Element != null)
- Element.DisplayRequested -= Display;
- }
-
- base.Dispose(disposing);
- }
-
- protected override void OnElementChanged(ElementChangedEventArgs e)
- {
- if (e.OldElement != null)
- e.OldElement.DisplayRequested -= Display;
-
- if (e.NewElement != null)
- {
- //var context = new EAGLContext(EAGLRenderingAPI.OpenGLES2);
- //var glkView = new GLKView(RectangleF.Empty) { Context = context, DrawableDepthFormat = GLKViewDrawableDepthFormat.Format24, Delegate = new Delegate(e.NewElement) };
- var glkView = new MacOSOpenGLView();
- SetNativeControl(glkView);
-
- e.NewElement.DisplayRequested += Display;
-
- SetupRenderLoop(false);
- }
-
- base.OnElementChanged(e);
- }
-
- protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- base.OnElementPropertyChanged(sender, e);
-
- if (e.PropertyName == OpenGLView.HasRenderLoopProperty.PropertyName)
- SetupRenderLoop(false);
- }
-
- void SetupRenderLoop(bool oneShot)
- {
- if (_displayLink != null)
- return;
- if (!oneShot && !Element.HasRenderLoop)
- return;
-
- _displayLink = new CVDisplayLink();
-
- //.Create(() =>
- //{
- // var control = Control;
- // var model = Element;
- // if (control != null)
- // control.Display();
- // if (control == null || model == null || !model.HasRenderLoop)
- // {
- // _displayLink.Invalidate();
- // _displayLink.Dispose();
- // _displayLink = null;
- // }
- //});
- //_displayLink.(NSRunLoop.Current, NSRunLoop.NSDefaultRunLoopMode);
- }
-
- //class Delegate : GLKViewDelegate
- //{
- // readonly OpenGLView _model;
-
- // public Delegate(OpenGLView model)
- // {
- // _model = model;
- // }
-
- // public override void DrawInRect(GLKView view, RectangleF rect)
- // {
- // var onDisplay = _model.OnDisplay;
- // if (onDisplay == null)
- // return;
- // onDisplay(rect.ToRectangle());
- // }
- //}
- }
-}
\ No newline at end of file
diff --git a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs
index eeddc6a3af62..36a3e6a60012 100644
--- a/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs
+++ b/src/Compatibility/Core/src/Tizen/Extensions/ColorExtensions.cs
@@ -1,6 +1,6 @@
using Microsoft.Maui.Graphics;
-using TColor = Tizen.UIExtensions.Common.Color;
using NColor = Tizen.NUI.Color;
+using TColor = Tizen.UIExtensions.Common.Color;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen
{
diff --git a/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs
index c67889f81364..eacaf83cce7a 100644
--- a/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs
+++ b/src/Compatibility/Core/src/Tizen/Extensions/DensityIndependentPixelExtensions.cs
@@ -1,8 +1,8 @@
using Microsoft.Maui.Graphics;
+using NSize = Tizen.NUI.Size2D;
using Rect = Microsoft.Maui.Graphics.Rect;
using TRect = Tizen.UIExtensions.Common.Rect;
using TSize = Tizen.UIExtensions.Common.Size;
-using NSize = Tizen.NUI.Size2D;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen
{
diff --git a/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs
index ceb048763645..072d623e9399 100644
--- a/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs
+++ b/src/Compatibility/Core/src/Tizen/Extensions/GeometryExtensions.cs
@@ -1,8 +1,8 @@
using System.Collections.Generic;
-using SkiaSharp;
using Microsoft.Maui.Controls.Shapes;
-using Rect = Microsoft.Maui.Graphics.Rect;
+using SkiaSharp;
using Point = Microsoft.Maui.Graphics.Point;
+using Rect = Microsoft.Maui.Graphics.Rect;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen
diff --git a/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs b/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs
index 63805730a753..5615170bc18b 100644
--- a/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs
+++ b/src/Compatibility/Core/src/Tizen/Extensions/TransformExtensions.cs
@@ -1,5 +1,5 @@
-using SkiaSharp;
using Microsoft.Maui.Controls.Shapes;
+using SkiaSharp;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen
{
diff --git a/src/Compatibility/Core/src/Tizen/Forms.cs b/src/Compatibility/Core/src/Tizen/Forms.cs
index 52ba88f09b07..be2a65eeff8a 100644
--- a/src/Compatibility/Core/src/Tizen/Forms.cs
+++ b/src/Compatibility/Core/src/Tizen/Forms.cs
@@ -5,12 +5,12 @@
using System.Reflection;
using Microsoft.Maui.Controls.Compatibility.Platform.Tizen;
using Microsoft.Maui.Controls.Internals;
-using Tizen.Applications;
using Microsoft.Maui.Devices;
+using Tizen.Applications;
using Color = Microsoft.Maui.Graphics.Color;
using NView = Tizen.NUI.BaseComponents.View;
-using TDeviceInfo = Tizen.UIExtensions.Common.DeviceInfo;
using Size = Microsoft.Maui.Graphics.Size;
+using TDeviceInfo = Tizen.UIExtensions.Common.DeviceInfo;
namespace Microsoft.Maui.Controls.Compatibility
{
@@ -28,6 +28,7 @@ public enum PlatformType
}
[Obsolete]
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public class InitializationOptions
{
public CoreApplication Context { get; set; }
@@ -47,6 +48,7 @@ public class InitializationOptions
public DisplayResolutionUnit DisplayResolutionUnit { get; set; }
public struct EffectScope
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public string Name;
public ExportEffectAttribute[] Effects;
diff --git a/src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs b/src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs
index ec2a1e435ce1..a996a314ba05 100644
--- a/src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs
+++ b/src/Compatibility/Core/src/Tizen/Gesture/PanGestureHandler.cs
@@ -1,6 +1,6 @@
+using GestureStateType = Tizen.NUI.Gesture.StateType;
using NGestureDetector = Tizen.NUI.GestureDetector;
using PanGestureDetector = Tizen.NUI.PanGestureDetector;
-using GestureStateType = Tizen.NUI.Gesture.StateType;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen
{
diff --git a/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs
index cd7fae1bd551..f89378221de6 100644
--- a/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs
+++ b/src/Compatibility/Core/src/Tizen/Renderers/BoxViewRenderer.cs
@@ -1,6 +1,6 @@
-using NView = Tizen.NUI.BaseComponents.View;
-using Tizen.UIExtensions.NUI;
using Microsoft.Maui.Controls.Platform;
+using Tizen.UIExtensions.NUI;
+using NView = Tizen.NUI.BaseComponents.View;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen
{
diff --git a/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs b/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs
index 01a64986dfbf..316657eed71a 100644
--- a/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs
+++ b/src/Compatibility/Core/src/Tizen/Renderers/VisualElementRenderer.cs
@@ -3,17 +3,17 @@
using System.ComponentModel;
using System.Linq;
using Microsoft.Maui.Controls.Internals;
-using Size = Microsoft.Maui.Graphics.Size;
-using Rect = Microsoft.Maui.Graphics.Rect;
-using Point = Microsoft.Maui.Graphics.Point;
using Microsoft.Maui.Controls.Platform;
using Tizen.NUI;
using Tizen.UIExtensions.Common;
-using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.VisualElement;
-using XFocusDirection = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.FocusDirection;
+using Tizen.UIExtensions.NUI;
using NView = Tizen.NUI.BaseComponents.View;
+using Point = Microsoft.Maui.Graphics.Point;
+using Rect = Microsoft.Maui.Graphics.Rect;
+using Size = Microsoft.Maui.Graphics.Size;
+using Specific = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.VisualElement;
using TPoint = Tizen.UIExtensions.Common.Point;
-using Tizen.UIExtensions.NUI;
+using XFocusDirection = Microsoft.Maui.Controls.PlatformConfiguration.TizenSpecific.FocusDirection;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Tizen
{
diff --git a/src/Compatibility/Core/src/WPF/Properties/AssemblyInfo.cs b/src/Compatibility/Core/src/WPF/Properties/AssemblyInfo.cs
index f4118d8b322b..7e336e347ee7 100644
--- a/src/Compatibility/Core/src/WPF/Properties/AssemblyInfo.cs
+++ b/src/Compatibility/Core/src/WPF/Properties/AssemblyInfo.cs
@@ -32,7 +32,6 @@
[assembly: ExportRenderer(typeof(ActivityIndicator), typeof(ActivityIndicatorRenderer))]
[assembly: ExportRenderer(typeof(Frame), typeof(FrameRenderer))]
[assembly: ExportRenderer(typeof(ListView), typeof(ListViewRenderer))]
-[assembly: ExportRenderer(typeof(OpenGLView), typeof(OpenGLViewRenderer))]
[assembly: ExportRenderer(typeof(ImageButton), typeof(ImageButtonRenderer))]
[assembly: ExportRenderer(typeof(EmbeddedFont), typeof(EmbeddedFontLoader))]
[assembly: ExportRenderer(typeof(Path), typeof(PathRenderer))]
diff --git a/src/Compatibility/Core/src/WPF/Renderers/OpenGLViewRenderer.cs b/src/Compatibility/Core/src/WPF/Renderers/OpenGLViewRenderer.cs
deleted file mode 100644
index d65b6d66f138..000000000000
--- a/src/Compatibility/Core/src/WPF/Renderers/OpenGLViewRenderer.cs
+++ /dev/null
@@ -1,133 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Windows.Forms;
-using System.Windows.Forms.Integration;
-using System.Windows.Threading;
-using OpenTK;
-using OpenTK.Graphics;
-
-namespace Microsoft.Maui.Controls.Compatibility.Platform.WPF
-{
- public class OpenGLViewRenderer : ViewRenderer
- {
- private GLControl _glControl;
- private DispatcherTimer _timer;
- private Action _action;
- private bool _hasRenderLoop;
- private bool _disposed;
-
- public Action Action
- {
- get { return _action; }
- set { _action = value; }
- }
-
- public bool HasRenderLoop
- {
- get { return _hasRenderLoop; }
- set { _hasRenderLoop = value; }
- }
-
- protected override void Dispose(bool disposing)
- {
- if (!_disposed && disposing)
- {
- _disposed = true;
-
- if (Element != null)
- ((IOpenGlViewController)Element).DisplayRequested -= Render;
-
- if (_glControl != null)
- _glControl.Paint -= OnPaint;
-
- if (_timer != null)
- _timer.Tick -= OnTick;
- }
-
- base.Dispose(disposing);
- }
-
- protected override void OnElementChanged(ElementChangedEventArgs e)
- {
- if (e.OldElement != null)
- ((IOpenGlViewController)e.OldElement).DisplayRequested -= Render;
-
- if (e.NewElement != null)
- {
- var windowsFormsHost = new WindowsFormsHost();
- _glControl = new GLControl(new GraphicsMode(32, 24), 2, 0, GraphicsContextFlags.Default);
- _glControl.MakeCurrent();
- _glControl.Dock = DockStyle.Fill;
-
- _glControl.Paint += OnPaint;
-
- windowsFormsHost.Child = _glControl;
- SetNativeControl(windowsFormsHost);
-
- _timer = new DispatcherTimer();
- _timer.Interval = TimeSpan.FromMilliseconds(16);
- _timer.Tick += OnTick;
- _timer.Start();
-
- ((IOpenGlViewController)e.NewElement).DisplayRequested += Render;
-
- SetRenderMode();
- SetupRenderAction();
- }
-
- base.OnElementChanged(e);
- }
-
- protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- base.OnElementPropertyChanged(sender, e);
-
- if (e.PropertyName == OpenGLView.HasRenderLoopProperty.PropertyName)
- {
- SetRenderMode();
- SetupRenderAction();
- }
- }
-
- public void Render(object sender, EventArgs eventArgs)
- {
- if (HasRenderLoop)
- return;
-
- SetupRenderAction();
- }
-
- private void SetRenderMode()
- {
- HasRenderLoop = Element.HasRenderLoop;
- }
-
- private void SetupRenderAction()
- {
- var model = Element;
- var onDisplay = model.OnDisplay;
-
- Action = onDisplay;
- }
-
- private void OnPaint(object sender, PaintEventArgs e)
- {
- if (_glControl == null)
- {
- return;
- }
-
- _glControl.MakeCurrent();
- Action.Invoke(new Rectangle(0, 0, _glControl.Width, _glControl.Height));
- _glControl.SwapBuffers();
- }
-
- private void OnTick(object sender, EventArgs e)
- {
- if (!HasRenderLoop)
- return;
-
- _glControl.Invalidate();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Compatibility/Core/src/Windows/AccessibilityExtensions.cs b/src/Compatibility/Core/src/Windows/AccessibilityExtensions.cs
index 32b334ac86ab..dbabe5c488a7 100644
--- a/src/Compatibility/Core/src/Windows/AccessibilityExtensions.cs
+++ b/src/Compatibility/Core/src/Windows/AccessibilityExtensions.cs
@@ -22,9 +22,13 @@ static string ConcatenateNameAndHint(Element Element)
{
string separator;
+#pragma warning disable CS0618 // Type or member is obsolete
var name = (string)Element.GetValue(AutomationProperties.NameProperty);
+#pragma warning restore CS0618 // Type or member is obsolete
+#pragma warning disable CS0618 // Type or member is obsolete
var hint = (string)Element.GetValue(AutomationProperties.HelpTextProperty);
+#pragma warning restore CS0618 // Type or member is obsolete
if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(hint))
diff --git a/src/Compatibility/Core/src/Windows/Forms.cs b/src/Compatibility/Core/src/Windows/Forms.cs
index 03f2af910ed0..b9d42d490fd5 100644
--- a/src/Compatibility/Core/src/Windows/Forms.cs
+++ b/src/Compatibility/Core/src/Windows/Forms.cs
@@ -13,7 +13,9 @@
namespace Microsoft.Maui.Controls.Compatibility
{
[Obsolete]
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct InitializationOptions
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public InitializationOptions(UI.Xaml.LaunchActivatedEventArgs args)
{
diff --git a/src/Compatibility/Core/src/iOS/Forms.cs b/src/Compatibility/Core/src/iOS/Forms.cs
index ca1031f43363..ab1b97cec3b4 100644
--- a/src/Compatibility/Core/src/iOS/Forms.cs
+++ b/src/Compatibility/Core/src/iOS/Forms.cs
@@ -33,7 +33,9 @@
namespace Microsoft.Maui.Controls.Compatibility
{
[Obsolete]
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct InitializationOptions
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
public InitializationFlags Flags;
}
diff --git a/src/Compatibility/Core/src/iOS/Renderers/OpenGLViewRenderer.cs b/src/Compatibility/Core/src/iOS/Renderers/OpenGLViewRenderer.cs
deleted file mode 100644
index d667cd1c2aa8..000000000000
--- a/src/Compatibility/Core/src/iOS/Renderers/OpenGLViewRenderer.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-#if !(MACCATALYST || MACOS)
-using System;
-using System.ComponentModel;
-using System.Runtime.Versioning;
-using CoreAnimation;
-using Foundation;
-using GLKit;
-using Microsoft.Maui.Controls.Platform;
-using OpenGLES;
-using RectangleF = CoreGraphics.CGRect;
-
-namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
-{
- [System.Obsolete]
- [UnsupportedOSPlatform("ios12.0")]
- [UnsupportedOSPlatform("tvos12.0")]
- internal class OpenGLViewRenderer : ViewRenderer
- {
- CADisplayLink _displayLink;
-
- [Microsoft.Maui.Controls.Internals.Preserve(Conditional = true)]
- public OpenGLViewRenderer()
- {
-
- }
-
- public void Display(object sender, EventArgs eventArgs)
- {
- if (Element.HasRenderLoop)
- return;
- SetupRenderLoop(true);
- }
-
- protected override void Dispose(bool disposing)
- {
- if (_displayLink != null)
- {
- _displayLink.Invalidate();
- _displayLink.Dispose();
- _displayLink = null;
-
- if (Element != null)
- Element.DisplayRequested -= Display;
- }
-
- base.Dispose(disposing);
- }
-
- protected override void OnElementChanged(ElementChangedEventArgs e)
- {
- if (e.OldElement != null)
- e.OldElement.DisplayRequested -= Display;
-
- if (e.NewElement != null)
- {
- var context = new EAGLContext(EAGLRenderingAPI.OpenGLES2);
- var glkView = new GLKView(RectangleF.Empty)
- {
- Context = context,
- DrawableDepthFormat = GLKViewDrawableDepthFormat.Format24,
- Delegate = new Delegate(e.NewElement)
- };
- SetNativeControl(glkView);
-
- e.NewElement.DisplayRequested += Display;
-
- SetupRenderLoop(false);
- }
-
- base.OnElementChanged(e);
- }
-
- protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- base.OnElementPropertyChanged(sender, e);
-
- if (e.PropertyName == OpenGLView.HasRenderLoopProperty.PropertyName)
- SetupRenderLoop(false);
- }
-
- void SetupRenderLoop(bool oneShot)
- {
- if (_displayLink != null)
- return;
- if (!oneShot && !Element.HasRenderLoop)
- return;
-
- _displayLink = CADisplayLink.Create(() =>
- {
- var control = Control;
- var model = Element;
- if (control != null)
- control.Display();
- if (control == null || model == null || !model.HasRenderLoop)
- {
- _displayLink?.Invalidate();
- _displayLink?.Dispose();
- _displayLink = null;
- }
- });
- _displayLink.AddToRunLoop(NSRunLoop.Current, NSRunLoopMode.Common);
- }
-
- class Delegate : GLKViewDelegate, IGLKViewDelegate
- {
- readonly OpenGLView _model;
-
- public Delegate(OpenGLView model)
- {
- _model = model;
- }
-
- public override void DrawInRect(GLKView view, RectangleF rect)
- {
- var onDisplay = _model.OnDisplay;
- if (onDisplay == null)
- return;
- onDisplay(rect.ToRectangle());
- }
- }
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/Compatibility/Maps/src/Android/Compatibility.Maps.Android.csproj b/src/Compatibility/Maps/src/Android/Compatibility.Maps.Android.csproj
index f5000b20f3f2..36553b5090eb 100644
--- a/src/Compatibility/Maps/src/Android/Compatibility.Maps.Android.csproj
+++ b/src/Compatibility/Maps/src/Android/Compatibility.Maps.Android.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Controls/Foldable/src/Controls.Foldable.csproj b/src/Controls/Foldable/src/Controls.Foldable.csproj
index 48cc66a92b56..05d41821f0c9 100644
--- a/src/Controls/Foldable/src/Controls.Foldable.csproj
+++ b/src/Controls/Foldable/src/Controls.Foldable.csproj
@@ -17,7 +17,7 @@
.NET MAUI Foldable provides additional APIs to better support foldable mobile devices.
icon.png
-
+
@@ -41,4 +41,6 @@
+
+
diff --git a/src/Controls/Maps/src/Controls.Maps.csproj b/src/Controls/Maps/src/Controls.Maps.csproj
index a1e02d622a5e..f9ae195f6822 100644
--- a/src/Controls/Maps/src/Controls.Maps.csproj
+++ b/src/Controls/Maps/src/Controls.Maps.csproj
@@ -31,4 +31,7 @@
+
+
+
\ No newline at end of file
diff --git a/src/Controls/docs/Microsoft.Maui.Controls/OpenGLView.xml b/src/Controls/docs/Microsoft.Maui.Controls/OpenGLView.xml
deleted file mode 100644
index 417a4d53bf3b..000000000000
--- a/src/Controls/docs/Microsoft.Maui.Controls/OpenGLView.xml
+++ /dev/null
@@ -1,314 +0,0 @@
-
-
-
-
-
-
- Microsoft.Maui.Controls.Core
- 0.0.0.0
- 1.0.0.0
- 1.1.0.0
- 1.2.0.0
- 1.3.0.0
- 1.4.0.0
- 1.5.0.0
- 2.0.0.0
-
-
- Microsoft.Maui.Controls.View
-
-
-
- Microsoft.Maui.Controls.IElementConfiguration<Microsoft.Maui.Controls.OpenGLView>
-
-
- Microsoft.Maui.Controls.IElementController
-
-
- Microsoft.Maui.Controls.IOpenGlViewController
-
-
- Microsoft.Maui.Controls.IViewController
-
-
- Microsoft.Maui.Controls.IVisualElementController
-
-
-
-
- Microsoft.Maui.Controls.RenderWith(typeof(Microsoft.Maui.Controls.Platform._OpenGLViewRenderer))
-
-
-
- A that displays OpenGL content.
-
-
- s are easiest to program using Shared Projects, in which case the reference to OpenTK is straightforward. The following example shows a simple OpenGL app with a render loop:
-
- {
-
- GL.ClearColor (red, green, blue, 1.0f);
- GL.Clear ((ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit));
-
- red += 0.01f;
- if (red >= 1.0f)
- red -= 1.0f;
- green += 0.02f;
- if (green >= 1.0f)
- green -= 1.0f;
- blue += 0.03f;
- if (blue >= 1.0f)
- blue -= 1.0f;
- };
-
- toggle.Toggled += (s, a) => {
- view.HasRenderLoop = toggle.IsToggled;
- };
- button.Clicked += (s, a) => view.Display ();
-
- var stack = new StackLayout {
- Padding = new Size (20, 20),
- Children = {view, toggle, button}
- };
-
- Content = stack;
- }
- }
-}
-
- ]]>
-
-
-
-
-
-
-
-
-
-
-
- Constructor
-
- 0.0.0.0
- 1.0.0.0
- 1.1.0.0
- 1.2.0.0
- 1.3.0.0
- 1.4.0.0
- 1.5.0.0
- 2.0.0.0
- Microsoft.Maui.Controls.Core
-
-
-
- Creates a new object with default values.
- To be added.
-
-
-
-
-
-
-
- Method
-
- 0.0.0.0
- 1.0.0.0
- 1.1.0.0
- 1.2.0.0
- 1.3.0.0
- 1.4.0.0
- 1.5.0.0
- 2.0.0.0
- Microsoft.Maui.Controls.Core
-
-
- System.Void
-
-
-
- Called prior to rendering.
- To be added.
-
-
-
-
-
-
-
- Event
-
- E:Microsoft.Maui.Controls.IOpenGlViewController.DisplayRequested
-
-
- 0.0.0.0
- 2.0.0.0
- Microsoft.Maui.Controls.Core
-
-
-
- System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)
-
-
-
- System.EventHandler
-
-
- For internal use by the Microsoft.Maui.Controls platform.
- To be added.
-
-
-
-
-
-
-
- Property
-
- 0.0.0.0
- 1.0.0.0
- 1.1.0.0
- 1.2.0.0
- 1.3.0.0
- 1.4.0.0
- 1.5.0.0
- 2.0.0.0
- Microsoft.Maui.Controls.Core
-
-
- System.Boolean
-
-
- Whether this has a custom rendering loop.
- To be added.
- To be added.
-
-
-
-
-
-
-
- Field
-
- 0.0.0.0
- 1.0.0.0
- 1.1.0.0
- 1.2.0.0
- 1.3.0.0
- 1.4.0.0
- 1.5.0.0
- 2.0.0.0
- Microsoft.Maui.Controls.Core
-
-
- Microsoft.Maui.Controls.BindableProperty
-
-
- Identifies the bindable property.
- To be added.
-
-
-
-
-
-
-
- Method
-
- M:Microsoft.Maui.Controls.IElementConfiguration`1.On``1
-
-
- 0.0.0.0
- 2.0.0.0
- Microsoft.Maui.Controls.Core
-
-
- Microsoft.Maui.Controls.IPlatformElementConfiguration<T,Microsoft.Maui.Controls.OpenGLView>
-
-
-
-
- Microsoft.Maui.Controls.IConfigPlatform
-
-
-
-
-
- To be added.
- Returns the platform-specific instance of this , on which a platform-specific method may be called.
- To be added.
- To be added.
-
-
-
-
-
-
-
- Property
-
- 0.0.0.0
- 1.0.0.0
- 1.1.0.0
- 1.2.0.0
- 1.3.0.0
- 1.4.0.0
- 1.5.0.0
- 2.0.0.0
- Microsoft.Maui.Controls.Core
-
-
- System.Action<Microsoft.Maui.Controls.Shapes.Rectangle>
-
-
- Overridden to create a custom rendering loop.
- To be added.
-
- When overridden, creates a custom renderer:
-
- {
-
- GL.ClearColor (red, green, blue, 1.0f);
- GL.Clear ((ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit));
-
- red += 0.01f;
- if (red >= 1.0f)
- red -= 1.0f;
- green += 0.02f;
- if (green >= 1.0f)
- green -= 1.0f;
- blue += 0.03f;
- if (blue >= 1.0f)
- blue -= 1.0f;
- };
- ]]>
-
-
-
-
-
-
diff --git a/src/Controls/samples/Controls.Sample.Profiling/Maui.Controls.Sample.Profiling.csproj b/src/Controls/samples/Controls.Sample.Profiling/Maui.Controls.Sample.Profiling.csproj
index 703d0b08be71..2dbb53f863ea 100644
--- a/src/Controls/samples/Controls.Sample.Profiling/Maui.Controls.Sample.Profiling.csproj
+++ b/src/Controls/samples/Controls.Sample.Profiling/Maui.Controls.Sample.Profiling.csproj
@@ -11,6 +11,8 @@
1
false
true
+
+ maccatalyst-x64
diff --git a/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj b/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj
index 66419a33a81f..ada765a27dd2 100644
--- a/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj
+++ b/src/Controls/samples/Controls.Sample.Sandbox/Maui.Controls.Sample.Sandbox.csproj
@@ -5,6 +5,8 @@
Exe
true
false
+
+ maccatalyst-x64
diff --git a/src/Controls/samples/Controls.Sample/Maui.Controls.Sample.csproj b/src/Controls/samples/Controls.Sample/Maui.Controls.Sample.csproj
index 7a6944e5632c..1bc3648494a3 100644
--- a/src/Controls/samples/Controls.Sample/Maui.Controls.Sample.csproj
+++ b/src/Controls/samples/Controls.Sample/Maui.Controls.Sample.csproj
@@ -8,6 +8,8 @@
Maui.Controls.Sample
false
$(NoWarn),CA1416
+
+ maccatalyst-x64
@@ -63,6 +65,7 @@
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml b/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml
index 474becca6092..389713023101 100644
--- a/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml
@@ -6,8 +6,36 @@
xmlns:pages="using:Maui.Controls.Sample.Pages"
xmlns:shellPages="clr-namespace:Maui.Controls.Sample.Pages.ShellGalleries"
FlyoutBackground="{AppThemeBinding Dark=Black, Light=White}"
- Title="Welcome to Shell"
- >
+ Title="{Binding ShellTitle}">
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml.cs
index a6604b6bc7e1..5507c6bab727 100644
--- a/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/AppShell.xaml.cs
@@ -12,8 +12,18 @@ public partial class AppShell
public AppShell()
{
InitializeComponent();
+ BindingContext = this;
SetTabBarBackgroundColor(this, Color.FromRgba(3, 169, 244, 255));
}
+
+ public string ShellTitle { get; set; } = "Welcome to Shell";
+
+ void OnChangeTabBarBackgroundColor(object sender, EventArgs e)
+ {
+ var random = new Random();
+
+ SetTabBarBackgroundColor(this, Color.FromRgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)));
+ }
}
public class PageSearchHandler : SearchHandler
diff --git a/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml
index 0ec45a7e3e32..fb03f1294eca 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml
@@ -3,16 +3,9 @@
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Pages.TabbedPageGallery"
+ xmlns:views="clr-namespace:Maui.Controls.Sample.Pages"
Title="Tabbed Page">
-
-
-
-
-
-
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml.cs
index 61b189504f44..53d7807573e1 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGallery.xaml.cs
@@ -14,77 +14,5 @@ public TabbedPageGallery()
this.Children.Add(new NavigationGallery());
this.Children.Add(new NavigationPage(new NavigationGallery()) { Title = "With Nav Page" });
}
-
- void OnTabbedPageAsRoot(object sender, EventArgs e)
- {
- var topTabs =
- new TabbedPage()
- {
- Children =
- {
- Handler.MauiContext.Services.GetRequiredService(),
- new NavigationPage(new Pages.NavigationGallery()) { Title = "Navigation Gallery" }
- }
- };
-
- this.Handler?.DisconnectHandler();
- Application.Current.MainPage?.Handler?.DisconnectHandler();
- Application.Current.MainPage = topTabs;
- }
-
- void OnSetToBottomTabs(object sender, EventArgs e)
- {
- var bottomTabs = new TabbedPage()
- {
- Children =
- {
- Handler.MauiContext.Services.GetRequiredService(),
- new NavigationPage(new Pages.NavigationGallery()) { Title = "Navigation Gallery" }
- }
- };
-
- this.Handler?.DisconnectHandler();
- Application.Current.MainPage?.Handler?.DisconnectHandler();
-
- AndroidSpecific.TabbedPage.SetToolbarPlacement(bottomTabs, AndroidSpecific.ToolbarPlacement.Bottom);
- Application.Current.MainPage = bottomTabs;
- }
-
- void OnChangeTabIndex(object sender, EventArgs e)
- {
- CurrentPage = Children[1];
- }
-
- void OnToggleTabBar(object sender, EventArgs e)
- {
- if ((this.BarBackground as SolidColorBrush)?.Color == SolidColorBrush.Purple.Color)
- this.BarBackground = null;
- else
- this.BarBackground = SolidColorBrush.Purple;
- }
-
- void OnToggleTabBarTextColor(object sender, EventArgs e)
- {
- if (this.BarTextColor == Colors.Green)
- this.BarTextColor = null;
- else
- this.BarTextColor = Colors.Green;
- }
-
- void OnToggleTabItemUnSelectedColor(object sender, EventArgs e)
- {
- if (this.UnselectedTabColor == Colors.Blue)
- this.UnselectedTabColor = null;
- else
- this.UnselectedTabColor = Colors.Blue;
- }
-
- void OnToggleTabItemSelectedColor(object sender, EventArgs e)
- {
- if (this.SelectedTabColor == Colors.Pink)
- this.SelectedTabColor = null;
- else
- this.SelectedTabColor = Colors.Pink;
- }
}
}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGalleryMainPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGalleryMainPage.xaml
new file mode 100644
index 000000000000..ffc91f8dd240
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGalleryMainPage.xaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGalleryMainPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGalleryMainPage.xaml.cs
new file mode 100644
index 000000000000..4ef4abb0b0b4
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Compatibility/TabbedPageGalleryMainPage.xaml.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Linq;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Graphics;
+using AndroidSpecific = Microsoft.Maui.Controls.PlatformConfiguration.AndroidSpecific;
+
+namespace Maui.Controls.Sample.Pages
+{
+ public partial class TabbedPageGalleryMainPage
+ {
+ public TabbedPageGalleryMainPage()
+ {
+ InitializeComponent();
+ }
+
+ TabbedPage _tabbedPage;
+ TabbedPage GetTabbedPage() => _tabbedPage ??= (TabbedPage)Parent;
+
+ void SetNewMainPage(Page page)
+ {
+ Application.Current.Windows[0].Page = page;
+ }
+
+ void OnTabbedPageAsRoot(object sender, EventArgs e)
+ {
+ var topTabs =
+ new TabbedPage()
+ {
+ Children =
+ {
+ Handler.MauiContext.Services.GetRequiredService(),
+ new NavigationPage(new Pages.NavigationGallery()) { Title = "Navigation Gallery" }
+ }
+ };
+
+ SetNewMainPage(topTabs);
+ }
+
+ void OnSetToBottomTabs(object sender, EventArgs e)
+ {
+ var bottomTabs = new TabbedPage()
+ {
+ Children =
+ {
+ Handler.MauiContext.Services.GetRequiredService(),
+ new NavigationPage(new Pages.NavigationGallery()) { Title = "Navigation Gallery" }
+ }
+ };
+
+ SetNewMainPage(bottomTabs);
+ AndroidSpecific.TabbedPage.SetToolbarPlacement(bottomTabs, AndroidSpecific.ToolbarPlacement.Bottom);
+ Application.Current.MainPage = bottomTabs;
+ }
+
+ void OnChangeTabIndex(object sender, EventArgs e)
+ {
+ GetTabbedPage().CurrentPage = GetTabbedPage().Children[1];
+ }
+
+ void OnToggleTabBar(object sender, EventArgs e)
+ {
+ if ((GetTabbedPage().BarBackground as SolidColorBrush)?.Color == SolidColorBrush.Purple.Color)
+ GetTabbedPage().BarBackground = null;
+ else
+ GetTabbedPage().BarBackground = SolidColorBrush.Purple;
+ }
+
+ void OnToggleTabBarTextColor(object sender, EventArgs e)
+ {
+ if (GetTabbedPage().BarTextColor == Colors.Green)
+ GetTabbedPage().BarTextColor = null;
+ else
+ GetTabbedPage().BarTextColor = Colors.Green;
+ }
+
+ void OnToggleTabItemUnSelectedColor(object sender, EventArgs e)
+ {
+ if (GetTabbedPage().UnselectedTabColor == Colors.Blue)
+ GetTabbedPage().UnselectedTabColor = null;
+ else
+ GetTabbedPage().UnselectedTabColor = Colors.Blue;
+ }
+
+ void OnToggleTabItemSelectedColor(object sender, EventArgs e)
+ {
+ if (GetTabbedPage().SelectedTabColor == Colors.Pink)
+ GetTabbedPage().SelectedTabColor = null;
+ else
+ GetTabbedPage().SelectedTabColor = Colors.Pink;
+ }
+
+ void OnRemoveTab(object sender, EventArgs e)
+ {
+ if (GetTabbedPage().Children.LastOrDefault() is TabbedPageGalleryMainPage mainPage)
+ {
+ GetTabbedPage().Children.Remove(mainPage);
+ }
+ }
+
+ void OnRemoveAllTabs(object sender, EventArgs e)
+ {
+ while (GetTabbedPage().Children.LastOrDefault() is TabbedPageGalleryMainPage mainPage)
+ {
+ GetTabbedPage().Children.Remove(mainPage);
+ }
+ }
+
+ void OnAddTab(object sender, EventArgs e)
+ {
+ GetTabbedPage()
+ .Children
+ .Add(new TabbedPageGalleryMainPage() { Title = $"Tab {GetTabbedPage().Children.Count}" });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/CollectionViewGallery.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/CollectionViewGallery.cs
index beaa8b4b78da..a810a470223a 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/CollectionViewGallery.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/CollectionViewGallery.cs
@@ -50,6 +50,7 @@ public CollectionViewGallery()
GalleryBuilder.NavButton("Alternate Layout Galleries", () => new AlternateLayoutGallery(), Navigation),
GalleryBuilder.NavButton("Header/Footer Galleries", () => new HeaderFooterGallery(), Navigation),
GalleryBuilder.NavButton("Nested CollectionViews", () => new NestedGalleries.NestedCollectionViewGallery(), Navigation),
+ GalleryBuilder.NavButton("Online images", () => new OnlineImages(), Navigation),
}
}
};
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/OnlineImages.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/OnlineImages.xaml
new file mode 100644
index 000000000000..652d71bbc66d
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/OnlineImages.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/OnlineImages.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/OnlineImages.xaml.cs
new file mode 100644
index 000000000000..653f6ef22124
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/CollectionViewGalleries/OnlineImages.xaml.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Xaml;
+using Microsoft.Maui.Dispatching;
+
+namespace Maui.Controls.Sample.Pages.CollectionViewGalleries
+{
+ public record OnlineImageInfo(string Uri);
+
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class OnlineImages : ContentPage
+ {
+ public OnlineImages()
+ {
+ InitializeComponent();
+
+ Dispatcher.DispatchAsync(SetItemsSource);
+ }
+
+ async Task SetItemsSource()
+ {
+ await Task.Delay(TimeSpan.FromSeconds(1));
+
+ CollectionView.ItemsSource = new ObservableCollection
+ {
+ new ("https://news.microsoft.com/wp-content/uploads/prod/2022/07/hexagon_print.gif"),
+ new ("https://news.microsoft.com/wp-content/uploads/prod/2022/07/collaboration-controls-in-power-platform_print.gif"),
+ new ("https://news.microsoft.com/wp-content/uploads/prod/2022/07/Updatesin-Teams.png"),
+ new ("https://news.microsoft.com/wp-content/uploads/prod/2022/07/Expanded-Reactions.png"),
+ new ("https://news.microsoft.com/wp-content/uploads/prod/2022/04/Companion-Devices.jpg"),
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml
index b302ecd7cc24..428960d7ceac 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml
@@ -52,6 +52,12 @@
]]>
+
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml.cs
index 9c07b4fe39d8..09020da56204 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/LabelPage.xaml.cs
@@ -1,4 +1,4 @@
-using Microsoft.Maui;
+using Maui.Controls.Sample.ViewModels;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
@@ -9,13 +9,15 @@ public partial class LabelPage
public LabelPage()
{
InitializeComponent();
+
+ BindingContext = new LabelViewModel();
}
- void ClickGestureRecognizer_Clicked(System.Object sender, System.EventArgs e)
+
+ void ClickGestureRecognizer_Clicked(object sender, System.EventArgs e)
{
var rnd = new System.Random();
- var span = sender as Span;
- if (span != null)
+ if (sender is Span span)
span.TextColor = Color.FromRgb((byte)rnd.Next(0, 254), (byte)rnd.Next(0, 254), (byte)rnd.Next(0, 254));
}
@@ -24,12 +26,12 @@ void ChangeFormattedString_Clicked(object sender, System.EventArgs e)
labelFormattedString.FormattedText = new FormattedString
{
Spans =
- {
- new Span
{
- Text = "Testing"
+ new Span
+ {
+ Text = "Testing"
+ }
}
- }
};
}
}
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/SliderPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/SliderPage.xaml
index da079ceaa4b8..92054c1ea705 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/SliderPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/SliderPage.xaml
@@ -43,8 +43,8 @@
-
-
+
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/SwipeViewGalleries/BasicSwipeGallery.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/SwipeViewGalleries/BasicSwipeGallery.xaml
index f16c2c71ef7c..0be6ffac934e 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/SwipeViewGalleries/BasicSwipeGallery.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/SwipeViewGalleries/BasicSwipeGallery.xaml
@@ -47,7 +47,7 @@
BackgroundColor="Green"/>
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml
index 06240032d8bb..e9ee83d3b1c0 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml
@@ -12,6 +12,7 @@
Text="HtmlWebViewSource (String)"
Style="{StaticResource Headline}"/>
@@ -31,6 +32,9 @@
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml.cs
index 3fe6680a9ced..7696658c333c 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Controls/WebViewPage.xaml.cs
@@ -28,6 +28,14 @@ protected override void OnDisappearing()
MauiWebView.Navigated -= OnMauiWebViewNavigated;
}
+ void OnUpdateHtmlSourceClicked(object sender, EventArgs args)
+ {
+ Random rnd = new();
+ HtmlWebViewSource htmlWebViewSource = new();
+ HtmlSourceWebView.Source = htmlWebViewSource;
+ htmlWebViewSource.Html += $"Updated Content {rnd.Next()}!
";
+ }
+
void OnGoBackClicked(object sender, EventArgs args)
{
Debug.WriteLine($"CanGoBack {MauiWebView.CanGoBack}");
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundGallery.xaml b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundGallery.xaml
new file mode 100644
index 000000000000..e6fae7a347e7
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundGallery.xaml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundGallery.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundGallery.xaml.cs
new file mode 100644
index 000000000000..072195b56e0c
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundGallery.xaml.cs
@@ -0,0 +1,10 @@
+namespace Maui.Controls.Sample.Pages
+{
+ public partial class ContentPageBackgroundGallery
+ {
+ public ContentPageBackgroundGallery()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGallery.xaml b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundImageGallery.xaml
similarity index 61%
rename from src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGallery.xaml
rename to src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundImageGallery.xaml
index edb658224e59..aade48a9b4f6 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGallery.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundImageGallery.xaml
@@ -1,16 +1,16 @@
+ Text="ContentPage"
+ VerticalOptions="Center"
+ HorizontalOptions="Center" />
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundImageGallery.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundImageGallery.xaml.cs
new file mode 100644
index 000000000000..a9708b358262
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageBackgroundImageGallery.xaml.cs
@@ -0,0 +1,10 @@
+namespace Maui.Controls.Sample.Pages
+{
+ public partial class ContentPageBackgroundImageGallery
+ {
+ public ContentPageBackgroundImageGallery()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageGallery.cs b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageGallery.cs
new file mode 100644
index 000000000000..a7842ac01fad
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGalleries/ContentPageGallery.cs
@@ -0,0 +1,33 @@
+using Microsoft.Maui;
+using Microsoft.Maui.Controls;
+using Microsoft.Maui.Controls.Internals;
+
+namespace Maui.Controls.Sample.Pages
+{
+ [Preserve(AllMembers = true)]
+ public class ContentPageGallery : ContentPage
+ {
+ public ContentPageGallery()
+ {
+ var descriptionLabel =
+ new Label { Text = "ContentPage Galleries", Margin = new Thickness(2, 2, 2, 2) };
+
+ Title = "ContentPage Galleries";
+
+ Content = new ScrollView
+ {
+ Content = new StackLayout
+ {
+ Children =
+ {
+ descriptionLabel,
+ GalleryBuilder.NavButton("ContentPage BackgroundImage", () =>
+ new ContentPageBackgroundImageGallery(), Navigation),
+ GalleryBuilder.NavButton("ContentPage Background", () =>
+ new ContentPageBackgroundGallery(), Navigation),
+ }
+ }
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGallery.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGallery.xaml.cs
deleted file mode 100644
index affb63b96b1c..000000000000
--- a/src/Controls/samples/Controls.Sample/Pages/Core/ContentPageGallery.xaml.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Maui.Controls.Sample.Pages
-{
- public partial class ContentPageGallery
- {
- public ContentPageGallery()
- {
- InitializeComponent();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml
index 26a69ac68560..4ba2119b2fcd 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Core/MultiWindowPage.xaml
@@ -10,6 +10,11 @@
Padding="12"
Spacing="6">
+
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml b/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml
index 2f172c9f2735..9b53278c5a1c 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml
+++ b/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml
@@ -10,6 +10,9 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml.cs b/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml.cs
index d521d9bbab60..a0654647e42d 100644
--- a/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml.cs
+++ b/src/Controls/samples/Controls.Sample/Pages/Layouts/ContentViewPage.xaml.cs
@@ -1,10 +1,37 @@
-namespace Maui.Controls.Sample.Pages
+using Microsoft.Maui.Controls;
+
+namespace Maui.Controls.Sample.Pages
{
public partial class ContentViewPage
{
public ContentViewPage()
{
InitializeComponent();
+
+ BindingContext = new ContentViewModel();
+ }
+ }
+
+ public class ContentViewModel : BindableObject
+ {
+ private string _text;
+
+ public ContentViewModel()
+ {
+ _text = "Content";
+ }
+
+ public string Text
+ {
+ get => _text;
+ set
+ {
+ if (_text != value)
+ {
+ _text = value;
+ OnPropertyChanged();
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Resources/Images/ic_flag.svg b/src/Controls/samples/Controls.Sample/Resources/Images/ic_flag.svg
new file mode 100644
index 000000000000..30421d49eac3
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Resources/Images/ic_flag.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Resources/Images/thumb_image.svg b/src/Controls/samples/Controls.Sample/Resources/Images/thumb_image.svg
new file mode 100644
index 000000000000..800274a089d3
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Resources/Images/thumb_image.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/ViewModels/LabelViewModel.cs b/src/Controls/samples/Controls.Sample/ViewModels/LabelViewModel.cs
new file mode 100644
index 000000000000..5f526a51f98e
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/ViewModels/LabelViewModel.cs
@@ -0,0 +1,24 @@
+using Maui.Controls.Sample.ViewModels.Base;
+
+namespace Maui.Controls.Sample.ViewModels
+{
+ public class LabelViewModel : BaseViewModel
+ {
+ string _htmlString;
+
+ public LabelViewModel()
+ {
+ HtmlString = "Html, <b>from ViewModel!</b>";
+ }
+
+ public string HtmlString
+ {
+ get { return _htmlString; }
+ set
+ {
+ _htmlString = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj b/src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj
index b0d8ba9038cc..cc550a4c2210 100644
--- a/src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj
+++ b/src/Controls/src/Build.Tasks/Controls.Build.Tasks.csproj
@@ -1,5 +1,4 @@
-
-
+
Microsoft.Maui.Controls.Build.Tasks
@@ -7,16 +6,21 @@
Microsoft.Maui.Controls.Build.Tasks
.NET MAUI MSBuild tasks. Enabled via <UseMaui>true</UseMaui>.
netstandard2.0
+ true
+
+ true
+
+ buildTransitive
+
true
- false
-
-
-
-
-
+
+
+
+
+
@@ -24,32 +28,60 @@
-
+
+
+
+
+
True
True
ErrorMessages.resx
-
-
-
ResXFileCodeGenerator
ErrorMessages.Designer.cs
-
+
- <_CopyItems Include="$(TargetDir)*.dll" Exclude="$(TargetDir)System.*.dll" />
+ <_CopyItems Include="nuget\buildTransitive\**" Exclude="nuget\buildTransitive\*;nuget\buildTransitive\netstandard2.0\**" />
+ <_CopyItems Include="nuget\buildTransitive\netstandard2.0\**" />
+ <_CopyItems Include="$(TargetDir)*.dll" Exclude="$(TargetDir)System.*.dll;$(TargetDir)Microsoft.Build.*" />
+ <_CopyItems Include="$(TargetDir)*.pdb" Exclude="$(TargetDir)System.*.pdb;$(TargetDir)Microsoft.Build.*" />
-
+
-
-
-
-
-
+
+
+
+ $(TargetsForTfmSpecificBuildOutput);
+ _MauiPackAdditionalAssemblies
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/Microsoft.Maui.Controls.Build.Tasks.props b/src/Controls/src/Build.Tasks/nuget/buildTransitive/Microsoft.Maui.Controls.Build.Tasks.props
new file mode 100644
index 000000000000..0d2bd1af724c
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/Microsoft.Maui.Controls.Build.Tasks.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/Microsoft.Maui.Controls.Build.Tasks.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/Microsoft.Maui.Controls.Build.Tasks.targets
new file mode 100644
index 000000000000..5fe8e7e82028
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/Microsoft.Maui.Controls.Build.Tasks.targets
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.Build.Tasks.props b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.Build.Tasks.props
new file mode 100644
index 000000000000..286993f36469
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.Build.Tasks.props
@@ -0,0 +1,9 @@
+
+
+
+ <_MicrosoftMauiControlsPlatformTargets>$(MSBuildThisFileDirectory)Microsoft.Maui.Controls.iOS.targets
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.Build.Tasks.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.Build.Tasks.targets
new file mode 100644
index 000000000000..963cdb5e4125
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.Build.Tasks.targets
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.iOS.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.iOS.targets
new file mode 100644
index 000000000000..09b77ba44420
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-ios10.0/Microsoft.Maui.Controls.iOS.targets
@@ -0,0 +1,7 @@
+
+
+
+ None
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.Build.Tasks.props b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.Build.Tasks.props
new file mode 100644
index 000000000000..cc541c53d708
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.Build.Tasks.props
@@ -0,0 +1,9 @@
+
+
+
+ <_MicrosoftMauiControlsPlatformTargets>$(MSBuildThisFileDirectory)Microsoft.Maui.Controls.MacCatalyst.targets
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.Build.Tasks.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.Build.Tasks.targets
new file mode 100644
index 000000000000..963cdb5e4125
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.Build.Tasks.targets
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.MacCatalyst.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.MacCatalyst.targets
new file mode 100644
index 000000000000..09b77ba44420
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-maccatalyst13.1/Microsoft.Maui.Controls.MacCatalyst.targets
@@ -0,0 +1,7 @@
+
+
+
+ None
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Controls.Build.Tasks.props b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Controls.Build.Tasks.props
new file mode 100644
index 000000000000..60ea3465b646
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Controls.Build.Tasks.props
@@ -0,0 +1,9 @@
+
+
+
+ $(MicrosoftMauiSdkPlatformTargets);$(MSBuildThisFileDirectory)Microsoft.Maui.Sdk.Windows.targets
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Controls.Build.Tasks.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Controls.Build.Tasks.targets
new file mode 100644
index 000000000000..963cdb5e4125
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Controls.Build.Tasks.targets
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Sdk.Windows.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Sdk.Windows.targets
new file mode 100644
index 000000000000..d1eef4fefd01
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/net6.0-windows10.0.17763.0/Microsoft.Maui.Sdk.Windows.targets
@@ -0,0 +1,16 @@
+
+
+
+
+ MSIX
+
+ true
+
+ false
+
+ false
+
+ true
+
+
+
diff --git a/src/Workload/Microsoft.Maui.Sdk/Sdk/Microsoft.Maui.Controls.Sdk.After.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.After.targets
similarity index 100%
rename from src/Workload/Microsoft.Maui.Sdk/Sdk/Microsoft.Maui.Controls.Sdk.After.targets
rename to src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.After.targets
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.Before.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.Before.targets
new file mode 100644
index 000000000000..f122c6362cb8
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.Before.targets
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.props b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.props
new file mode 100644
index 000000000000..164975bf0283
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.props
@@ -0,0 +1,10 @@
+
+
+
+
+ <_MauiSkipSdkAutoImport>true
+
+
+
+
+
diff --git a/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.targets
new file mode 100644
index 000000000000..d77cfba900d8
--- /dev/null
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Build.Tasks.targets
@@ -0,0 +1,13 @@
+
+
+
+ true
+
+
+
+
+
+ $(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)Microsoft.Maui.Controls.Build.Tasks.After.targets
+
+
+
\ No newline at end of file
diff --git a/.nuspec/Microsoft.Maui.Controls.props b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets
similarity index 81%
rename from .nuspec/Microsoft.Maui.Controls.props
rename to src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets
index 79ed0e9a0e40..d86238a61e44 100644
--- a/.nuspec/Microsoft.Maui.Controls.props
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Common.targets
@@ -1,12 +1,9 @@
-
-
<_IsHotRestartDefined>$([System.Text.RegularExpressions.Regex]::IsMatch('$(DefineConstants.Trim())', '(^|;)HOTRESTART($|;)'))
HOTRESTART;$(DefineConstants)
True
- None
diff --git a/.nuspec/Microsoft.Maui.Controls.DefaultItems.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.DefaultItems.targets
similarity index 99%
rename from .nuspec/Microsoft.Maui.Controls.DefaultItems.targets
rename to src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.DefaultItems.targets
index 98969304935f..3b8a7fa304e1 100644
--- a/.nuspec/Microsoft.Maui.Controls.DefaultItems.targets
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.DefaultItems.targets
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Workload/Microsoft.Maui.Sdk/Sdk/AutoImport.in.props b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Globs.props
similarity index 76%
rename from src/Workload/Microsoft.Maui.Sdk/Sdk/AutoImport.in.props
rename to src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Globs.props
index a03491409cde..70e85541920f 100644
--- a/src/Workload/Microsoft.Maui.Sdk/Sdk/AutoImport.in.props
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.Globs.props
@@ -1,5 +1,4 @@
-
@@ -8,7 +7,7 @@
-
+
@@ -31,7 +30,7 @@
-
+
@@ -42,7 +41,7 @@
-->
-
+
@@ -56,7 +55,7 @@
-
+
-
+
-
+
@@ -153,4 +152,14 @@
+
+
+
+
+
+
diff --git a/.nuspec/Microsoft.Maui.Controls.SingleProject.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
similarity index 85%
rename from .nuspec/Microsoft.Maui.Controls.SingleProject.targets
rename to src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
index 628e932bee6d..0a64616ac8db 100644
--- a/.nuspec/Microsoft.Maui.Controls.SingleProject.targets
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets
@@ -128,40 +128,10 @@
-
-
-
-
-
-
- <_MauiAppxManifest Include="@(AppxManifest)" />
-
-
-
-
-
$(MSBuildExtensionsPath)\Microsoft\VisualStudio\Maui\Maui.DesignTime.targets
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.nuspec/Microsoft.Maui.Controls.targets b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets
similarity index 94%
rename from .nuspec/Microsoft.Maui.Controls.targets
rename to src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets
index afbfa45a65e3..8831437fc278 100644
--- a/.nuspec/Microsoft.Maui.Controls.targets
+++ b/src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.targets
@@ -3,7 +3,6 @@
- <_MinimumMauiWorkloadVersion>6.0.200
true
True
True
@@ -14,7 +13,6 @@
-
@@ -46,9 +44,6 @@
-
-
-
+
+
diff --git a/src/Controls/src/Core/Application.cs b/src/Controls/src/Core/Application.cs
index 193c8a1d8b3a..ebf921c16f48 100644
--- a/src/Controls/src/Core/Application.cs
+++ b/src/Controls/src/Core/Application.cs
@@ -110,10 +110,6 @@ public Page? MainPage
}
}
- ///
- [Obsolete("Properties API is obsolete, use Microsoft.Maui.Storage.Preferences instead.", error: true)]
- public IDictionary Properties => throw new NotSupportedException("Properties API is obsolete, use Microsoft.Maui.Storage.Preferences instead.");
-
internal override IReadOnlyList LogicalChildrenInternal =>
_logicalChildren ??= new ReadOnlyCollection(InternalChildren);
@@ -273,10 +269,6 @@ internal void NotifyOfWindowModalEvent(EventArgs eventArgs)
public event EventHandler? PageDisappearing;
- ///
- [Obsolete("Properties API is obsolete, use Microsoft.Maui.Storage.Preferences instead.", error: true)]
- public Task SavePropertiesAsync() => throw new NotSupportedException("Properties API is obsolete, use Microsoft.Maui.Storage.Preferences instead.");
-
///
public IPlatformElementConfiguration On() where T : IConfigPlatform
{
diff --git a/src/Controls/src/Core/AutomationProperties.cs b/src/Controls/src/Core/AutomationProperties.cs
index 91e66ed2135c..33dbebcf8d45 100644
--- a/src/Controls/src/Core/AutomationProperties.cs
+++ b/src/Controls/src/Core/AutomationProperties.cs
@@ -1,10 +1,13 @@
#nullable disable
+using System;
+
namespace Microsoft.Maui.Controls
{
///
public class AutomationProperties
{
///
+ [Obsolete("Use SemanticProperties.Hint instead. See the conceptual docs about accessibility for more information.")]
public static readonly BindableProperty HelpTextProperty = BindableProperty.Create("HelpText", typeof(string), typeof(AutomationProperties), default(string));
///
@@ -13,15 +16,19 @@ public class AutomationProperties
public static readonly BindableProperty ExcludedWithChildrenProperty = BindableProperty.Create("ExcludedWithChildren", typeof(bool?), typeof(AutomationProperties), null);
///
+ [Obsolete("Use a SemanticProperties.Description binding instead. See the conceptual docs about accessibility for more information.")]
public static readonly BindableProperty LabeledByProperty = BindableProperty.Create("LabeledBy", typeof(VisualElement), typeof(AutomationProperties), default(VisualElement));
///
+ [Obsolete("Use SemanticProperties.Description instead. See the conceptual docs about accessibility for more information.")]
public static readonly BindableProperty NameProperty = BindableProperty.Create("Name", typeof(string), typeof(AutomationProperties), default(string));
///
public static string GetHelpText(BindableObject bindable)
{
+#pragma warning disable CS0618 // Type or member is obsolete
return (string)bindable.GetValue(HelpTextProperty);
+#pragma warning restore CS0618 // Type or member is obsolete
}
///
@@ -39,19 +46,25 @@ public static string GetHelpText(BindableObject bindable)
[System.ComponentModel.TypeConverter(typeof(ReferenceTypeConverter))]
public static VisualElement GetLabeledBy(BindableObject bindable)
{
+#pragma warning disable CS0618 // Type or member is obsolete
return (VisualElement)bindable.GetValue(LabeledByProperty);
+#pragma warning restore CS0618 // Type or member is obsolete
}
///
public static string GetName(BindableObject bindable)
{
+#pragma warning disable CS0618 // Type or member is obsolete
return (string)bindable.GetValue(NameProperty);
+#pragma warning restore CS0618 // Type or member is obsolete
}
///
public static void SetHelpText(BindableObject bindable, string value)
{
+#pragma warning disable CS0618 // Type or member is obsolete
bindable.SetValue(HelpTextProperty, value);
+#pragma warning restore CS0618 // Type or member is obsolete
}
///
@@ -68,13 +81,17 @@ public static void SetExcludedWithChildren(BindableObject bindable, bool? value)
///
public static void SetLabeledBy(BindableObject bindable, VisualElement value)
{
+#pragma warning disable CS0618 // Type or member is obsolete
bindable.SetValue(LabeledByProperty, value);
+#pragma warning restore CS0618 // Type or member is obsolete
}
///
public static void SetName(BindableObject bindable, string value)
{
+#pragma warning disable CS0618 // Type or member is obsolete
bindable.SetValue(NameProperty, value);
+#pragma warning restore CS0618 // Type or member is obsolete
}
}
}
diff --git a/src/Controls/src/Core/BindableObject.cs b/src/Controls/src/Core/BindableObject.cs
index ab9a93d90853..04424724fd5f 100644
--- a/src/Controls/src/Core/BindableObject.cs
+++ b/src/Controls/src/Core/BindableObject.cs
@@ -31,7 +31,7 @@ public BindableObject()
readonly Dictionary _properties = new Dictionary(4);
bool _applying;
- object _inheritedContext;
+ WeakReference _inheritedContext;
///
public static readonly BindableProperty BindingContextProperty =
@@ -41,7 +41,7 @@ public BindableObject()
///
public object BindingContext
{
- get => _inheritedContext ?? GetValue(BindingContextProperty);
+ get => _inheritedContext?.Target ?? GetValue(BindingContextProperty);
set => SetValue(BindingContextProperty, value);
}
@@ -238,7 +238,7 @@ public static void SetInheritedBindingContext(BindableObject bindable, object va
if (bpContext != null && ((bpContext.Attributes & BindableContextAttributes.IsManuallySet) != 0))
return;
- object oldContext = bindable._inheritedContext;
+ object oldContext = bindable._inheritedContext?.Target;
if (ReferenceEquals(oldContext, value))
return;
@@ -253,7 +253,7 @@ public static void SetInheritedBindingContext(BindableObject bindable, object va
}
else
{
- bindable._inheritedContext = value;
+ bindable._inheritedContext = new WeakReference(value);
}
bindable.ApplyBindings(skipBindingContext: false, fromBindingContextChanged: true);
@@ -557,7 +557,7 @@ internal void ApplyBindings(bool skipBindingContext, bool fromBindingContextChan
static void BindingContextPropertyBindingChanging(BindableObject bindable, BindingBase oldBindingBase, BindingBase newBindingBase)
{
- object context = bindable._inheritedContext;
+ object context = bindable._inheritedContext?.Target;
var oldBinding = oldBindingBase as Binding;
var newBinding = newBindingBase as Binding;
diff --git a/src/Controls/src/Core/BindingExpression.cs b/src/Controls/src/Core/BindingExpression.cs
index 57bed11e3cbb..ab1fb95294f8 100644
--- a/src/Controls/src/Core/BindingExpression.cs
+++ b/src/Controls/src/Core/BindingExpression.cs
@@ -635,7 +635,7 @@ public void SubscribeTo(INotifyPropertyChanged source, PropertyChangedEventHandl
_listener.SetTarget(listener);
}
- public void Unsubscribe()
+ public void Unsubscribe(bool finalizer = false)
{
INotifyPropertyChanged source;
if (_source.TryGetTarget(out source) && source != null)
@@ -644,6 +644,10 @@ public void Unsubscribe()
if (bo != null)
bo.BindingContextChanged -= _bchandler;
+ // If we are called from a finalizer, WeakReference.SetTarget() can throw InvalidOperationException
+ if (finalizer)
+ return;
+
_source.SetTarget(null);
_listener.SetTarget(null);
}
@@ -668,6 +672,8 @@ class BindingExpressionPart
readonly PropertyChangedEventHandler _changeHandler;
WeakPropertyChangedProxy _listener;
+ ~BindingExpressionPart() => _listener?.Unsubscribe(finalizer: true);
+
public BindingExpressionPart(BindingExpression expression, string content, bool isIndexer = false)
{
_expression = expression;
diff --git a/src/Controls/src/Core/Brush.cs b/src/Controls/src/Core/Brush.cs
index 3cf80d7978c1..d4fc16021c19 100644
--- a/src/Controls/src/Core/Brush.cs
+++ b/src/Controls/src/Core/Brush.cs
@@ -7,11 +7,9 @@ namespace Microsoft.Maui.Controls
[System.ComponentModel.TypeConverter(typeof(BrushTypeConverter))]
public abstract partial class Brush : Element
{
+ static ImmutableBrush defaultBrush;
///
- public static Brush Default
- {
- get { return new SolidColorBrush(null); }
- }
+ public static Brush Default => defaultBrush ??= new(null);
public static implicit operator Brush(Color color) => new SolidColorBrush(color);
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs
index 3d141d78ba99..7d5191eeb766 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Android/FrameRenderer.cs
@@ -4,6 +4,7 @@
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Views;
+using Android.Views.Animations;
using AndroidX.CardView.Widget;
using AndroidX.Core.View;
using Microsoft.Maui.Controls.Platform;
@@ -52,7 +53,6 @@ public static IPropertyMapper Mapper
public static CommandMapper CommandMapper
= new CommandMapper(ViewRenderer.VisualElementRendererCommandMapper);
-
float _defaultElevation = -1f;
float _defaultCornerRadius = -1f;
@@ -68,6 +68,8 @@ public static CommandMapper CommandMapper
public event EventHandler? ElementChanged;
public event EventHandler? ElementPropertyChanged;
+ const double LegacyMinimumFrameSize = 20;
+
public FrameRenderer(Context context) : this(context, Mapper)
{
}
@@ -96,17 +98,28 @@ protected Frame? Element
}
}
- Size IViewHandler.GetDesiredSize(double widthMeasureSpec, double heightMeasureSpec)
+ Size IViewHandler.GetDesiredSize(double widthConstraint, double heightConstraint)
{
- double minWidth = 20;
- if (Primitives.Dimension.IsExplicitSet(widthMeasureSpec) && !double.IsInfinity(widthMeasureSpec))
- minWidth = widthMeasureSpec;
+ var virtualView = (this as IViewHandler)?.VirtualView;
+ if (virtualView is null)
+ {
+ return Size.Zero;
+ }
+
+ var minWidth = virtualView.MinimumWidth;
+ var minHeight = virtualView.MinimumHeight;
- double minHeight = 20;
- if (Primitives.Dimension.IsExplicitSet(widthMeasureSpec) && !double.IsInfinity(heightMeasureSpec))
- minHeight = heightMeasureSpec;
+ if (!Primitives.Dimension.IsExplicitSet(minWidth))
+ {
+ minWidth = LegacyMinimumFrameSize;
+ }
+
+ if (!Primitives.Dimension.IsExplicitSet(minHeight))
+ {
+ minHeight = LegacyMinimumFrameSize;
+ }
- return VisualElementRenderer.GetDesiredSize(this, widthMeasureSpec, heightMeasureSpec,
+ return VisualElementRenderer.GetDesiredSize(this, widthConstraint, heightConstraint,
new Size(minWidth, minHeight));
}
diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs
index 0b96b2f9cd67..a0e390947e65 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/CellRenderer.cs
@@ -76,6 +76,7 @@ public virtual void SetAccessibility(UITableViewCell tableViewCell, Cell cell)
else
tableViewCell.AccessibilityElementsHidden = false;
+#pragma warning disable CS0618 // Type or member is obsolete
if (cell.IsSet(AutomationProperties.NameProperty))
tableViewCell.AccessibilityLabel = cell.GetValue(AutomationProperties.NameProperty).ToString();
else
@@ -85,6 +86,8 @@ public virtual void SetAccessibility(UITableViewCell tableViewCell, Cell cell)
tableViewCell.AccessibilityHint = cell.GetValue(AutomationProperties.HelpTextProperty).ToString();
else
tableViewCell.AccessibilityHint = null;
+#pragma warning restore CS0618 // Type or member is obsolete
+
}
public virtual void SetBackgroundColor(UITableViewCell tableViewCell, Cell cell, UIColor color)
diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/EntryCellRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/EntryCellRenderer.cs
index 16113d0a6ff9..4ec82b41fa40 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/EntryCellRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/EntryCellRenderer.cs
@@ -183,7 +183,7 @@ static bool OnShouldReturn(UITextField view)
if (handler != null)
handler(realCell, EventArgs.Empty);
- view.ResignFirstResponder();
+ KeyboardAutoManager.GoToNextResponderOrResign(view);
return true;
}
diff --git a/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs
index 73a51d9e34bf..789d88e6d0a6 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs
@@ -5,6 +5,7 @@
using System.Linq;
using System.Threading.Tasks;
using CoreGraphics;
+using Foundation;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;
@@ -42,8 +43,9 @@ public class NavigationRenderer : UINavigationController, IPlatformViewHandler
ViewHandlerDelegator _viewHandlerWrapper;
bool _navigating = false;
VisualElement _element;
+ bool _uiRequestedPop; // User tapped the back button or swiped to navigate back
- [Preserve(Conditional = true)]
+ [Internals.Preserve(Conditional = true)]
public NavigationRenderer() : base(typeof(MauiControlsNavigationBar), null)
{
_viewHandlerWrapper = new ViewHandlerDelegator(Mapper, CommandMapper, this);
@@ -780,7 +782,7 @@ void UpdateToolBarVisible()
TopViewController?.NavigationItem?.TitleView?.LayoutSubviews();
}
- internal async Task UpdateFormsInnerNavigation(Page pageBeingRemoved)
+ async Task UpdateFormsInnerNavigation(Page pageBeingRemoved)
{
if (NavPage == null)
return;
@@ -789,9 +791,24 @@ internal async Task UpdateFormsInnerNavigation(Page pageBeingRemoved)
_ignorePopCall = true;
if (Element.Navigation.NavigationStack.Contains(pageBeingRemoved))
+ {
await (NavPage as INavigationPageController)?.RemoveAsyncInner(pageBeingRemoved, false, true);
+ if (_uiRequestedPop)
+ {
+ NavPage?.SendNavigatedFromHandler(pageBeingRemoved);
+ }
+ }
+
_ignorePopCall = false;
+ _uiRequestedPop = false;
+ }
+ [Export("navigationBar:shouldPopItem:")]
+ [Internals.Preserve(Conditional = true)]
+ internal bool ShouldPopItem(UINavigationBar _, UINavigationItem __)
+ {
+ _uiRequestedPop = true;
+ return true;
}
internal static void SetFlyoutLeftBarButton(UIViewController containerController, FlyoutPage FlyoutPage)
@@ -844,7 +861,9 @@ static void SetAccessibilityHint(UIBarButtonItem uIBarButtonItem, Element elemen
if (_defaultAccessibilityHint == null)
_defaultAccessibilityHint = uIBarButtonItem.AccessibilityHint;
+#pragma warning disable CS0618 // Type or member is obsolete
uIBarButtonItem.AccessibilityHint = (string)element.GetValue(AutomationProperties.HelpTextProperty) ?? _defaultAccessibilityHint;
+#pragma warning restore CS0618 // Type or member is obsolete
}
static void SetAccessibilityLabel(UIBarButtonItem uIBarButtonItem, Element element)
@@ -855,7 +874,9 @@ static void SetAccessibilityLabel(UIBarButtonItem uIBarButtonItem, Element eleme
if (_defaultAccessibilityLabel == null)
_defaultAccessibilityLabel = uIBarButtonItem.AccessibilityLabel;
+#pragma warning disable CS0618 // Type or member is obsolete
uIBarButtonItem.AccessibilityLabel = (string)element.GetValue(AutomationProperties.NameProperty) ?? _defaultAccessibilityLabel;
+#pragma warning restore CS0618 // Type or member is obsolete
}
static void SetIsAccessibilityElement(UIBarButtonItem uIBarButtonItem, Element element)
@@ -959,7 +980,9 @@ void SetupLines()
class MauiNavigationDelegate : UINavigationControllerDelegate
{
+ bool _finishedWithInitialNavigation;
readonly WeakReference _navigation;
+
public MauiNavigationDelegate(NavigationRenderer navigationRenderer)
{
_navigation = new WeakReference(navigationRenderer);
@@ -974,6 +997,12 @@ public override void DidShowViewController(UINavigationController navigationCont
{
pvc.UpdateFrames();
}
+
+ if (r.Element is NavigationPage np && !_finishedWithInitialNavigation)
+ {
+ _finishedWithInitialNavigation = true;
+ np.SendNavigatedFromHandler(null);
+ }
}
}
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFlyoutTemplatedContentRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFlyoutTemplatedContentRenderer.cs
index 520c0df76dac..97c71eca0f15 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFlyoutTemplatedContentRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFlyoutTemplatedContentRenderer.cs
@@ -123,21 +123,17 @@ protected virtual void LoadView(IShellContext shellContext)
// so we want to delay loading to the latest possible point in time so
// it doesn't delay initial startup.
GenericGlobalLayoutListener ggll = null;
- ggll = new GenericGlobalLayoutListener(InitialLoad);
- sfl.ViewTreeObserver.AddOnGlobalLayoutListener(ggll);
+ ggll = new GenericGlobalLayoutListener(InitialLoad, sfl);
- void InitialLoad()
+ void InitialLoad(GenericGlobalLayoutListener listener, AView view)
{
OnFlyoutViewLayoutChanging();
if (_flyoutContentView == null || ggll == null)
return;
- var listener = ggll;
ggll = null;
-
- // Once initial load has finished let's just attach to Layout Changing
- sfl.ViewTreeObserver.RemoveOnGlobalLayoutListener(listener);
+ listener.Invalidate();
sfl.LayoutChanging += OnFlyoutViewLayoutChanging;
}
}
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFragmentContainer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFragmentContainer.cs
index 8907188e6015..e766431077d0 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFragmentContainer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellFragmentContainer.cs
@@ -23,32 +23,9 @@ public ShellFragmentContainer(ShellContent shellContent, IMauiContext mauiContex
public override AView OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
_page = ((IShellContentController)ShellContentTab).GetOrCreateContent();
+ _page.ToPlatform(_mauiContext, RequireContext(), inflater, ChildFragmentManager);
- IMauiContext mauiContext = null;
-
- // If the page has already been created with a handler then we just let it retain the same
- // Handler and MauiContext
- // But we want to update the inflater and ChildFragmentManager to match
- // the handlers new home
- if (_page.Handler?.MauiContext is MauiContext scopedMauiContext)
- {
- // If this page comes to us from a different activity then don't reuse it
- // disconnect the handler so it can recreate against new MauiContext
- if (scopedMauiContext.GetActivity() == Context.GetActivity())
- {
- scopedMauiContext.AddWeakSpecific(ChildFragmentManager);
- scopedMauiContext.AddWeakSpecific(inflater);
- mauiContext = scopedMauiContext;
- }
- else
- {
- _page.Handler.DisconnectHandler();
- }
- }
-
- mauiContext ??= _mauiContext.MakeScoped(layoutInflater: inflater, fragmentManager: ChildFragmentManager);
-
- return new ShellPageContainer(RequireContext(), (IPlatformViewHandler)_page.ToHandler(mauiContext), true)
+ return new ShellPageContainer(RequireContext(), (IPlatformViewHandler)_page.Handler, true)
{
LayoutParameters = new LP(LP.MatchParent, LP.MatchParent)
};
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs
index 25ecac653611..d969e5691f27 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellItemRenderer.cs
@@ -12,6 +12,7 @@
using Google.Android.Material.BottomSheet;
using Google.Android.Material.Navigation;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Microsoft.Maui.Graphics;
using AColor = Android.Graphics.Color;
using AView = Android.Views.View;
@@ -38,7 +39,7 @@ void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance)
{
_shellAppearance = appearance;
- if (appearance != null)
+ if (appearance is not null)
SetAppearance(appearance);
else
ResetAppearance();
@@ -59,6 +60,9 @@ void IAppearanceObserver.OnAppearanceChanged(ShellAppearance appearance)
bool _appearanceSet;
public IShellItemController ShellItemController => ShellItem;
IMauiContext MauiContext => ShellContext.Shell.Handler.MauiContext;
+ IMenuItem _updateMenuItemTitle;
+ IMenuItem _updateMenuItemIcon;
+ ShellSection _updateMenuItemSource;
public ShellItemRenderer(IShellContext shellContext) : base(shellContext)
{
@@ -73,10 +77,10 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,
_navigationArea = PlatformInterop.CreateNavigationBarArea(context, _outerLayout);
_bottomView = PlatformInterop.CreateNavigationBar(context, Resource.Attribute.bottomNavigationViewStyle, _outerLayout, this);
- if (ShellItem == null)
+ if (ShellItem is null)
throw new InvalidOperationException("Active Shell Item not set. Have you added any Shell Items to your Shell?");
- if (ShellItem.CurrentItem == null)
+ if (ShellItem.CurrentItem is null)
throw new InvalidOperationException($"Content not found for active {ShellItem}. Title: {ShellItem.Title}. Route: {ShellItem.Route}.");
HookEvents(ShellItem);
@@ -92,12 +96,12 @@ public override AView OnCreateView(LayoutInflater inflater, ViewGroup container,
void Destroy()
{
- if (ShellItem != null)
+ if (ShellItem is not null)
UnhookEvents(ShellItem);
((IShellController)ShellContext?.Shell)?.RemoveAppearanceObserver(this);
- if (_bottomSheetDialog != null)
+ if (_bottomSheetDialog is not null)
{
_bottomSheetDialog.DismissEvent -= OnMoreSheetDismissed;
_bottomSheetDialog?.Dispose();
@@ -108,7 +112,7 @@ void Destroy()
_appearanceTracker?.Dispose();
_outerLayout?.Dispose();
- if (_bottomView != null)
+ if (_bottomView is not null)
{
_bottomView?.SetOnItemSelectedListener(null);
_bottomView?.Background?.Dispose();
@@ -143,9 +147,9 @@ public override void OnDestroy()
protected virtual void SetAppearance(ShellAppearance appearance)
{
- if (_bottomView == null ||
+ if (_bottomView is null ||
_bottomView.Visibility == ViewStates.Gone ||
- DisplayedPage == null)
+ DisplayedPage is null)
{
return;
}
@@ -229,7 +233,7 @@ void clickCallback(object s, EventArgs e)
(result) =>
{
image.SetImageDrawable(result?.Value);
- if (result?.Value != null)
+ if (result?.Value is not null)
{
var color = Colors.Black.MultiplyAlpha(0.6f).ToPlatform();
result.Value.SetTint(color);
@@ -287,13 +291,13 @@ protected override void OnDisplayedPageChanged(Page newPage, Page oldPage)
{
base.OnDisplayedPageChanged(newPage, oldPage);
- if (oldPage != null)
+ if (oldPage is not null)
oldPage.PropertyChanged -= OnDisplayedElementPropertyChanged;
- if (newPage != null)
+ if (newPage is not null)
newPage.PropertyChanged += OnDisplayedElementPropertyChanged;
- if (newPage != null && !_menuSetup)
+ if (newPage is not null && !_menuSetup)
{
SetupMenu();
}
@@ -358,7 +362,7 @@ protected virtual void OnMoreSheetDismissed(object sender, EventArgs e)
{
OnShellSectionChanged();
- if (_bottomSheetDialog != null)
+ if (_bottomSheetDialog is not null)
{
_bottomSheetDialog.DismissEvent -= OnMoreSheetDismissed;
_bottomSheetDialog.Dispose();
@@ -377,24 +381,53 @@ protected override void OnShellSectionPropertyChanged(object sender, PropertyCha
{
base.OnShellSectionPropertyChanged(sender, e);
- if (e.PropertyName == BaseShellItem.IsEnabledProperty.PropertyName)
+ if (e.IsOneOf(BaseShellItem.TitleProperty, BaseShellItem.IconProperty, BaseShellItem.IsEnabledProperty))
{
- var content = (ShellSection)sender;
- var index = ((IShellItemController)ShellItem).GetItems().IndexOf(content);
+ var shellSection = (ShellSection)sender;
+ var index = ((IShellItemController)ShellItem).GetItems().IndexOf(shellSection);
var itemCount = ((IShellItemController)ShellItem).GetItems().Count;
var maxItems = _bottomView.MaxItemCount;
+ IMenuItem menuItem = null;
- if (itemCount > maxItems && index > maxItems - 2)
- return;
+ if (!(itemCount > maxItems && index > maxItems - 2))
+ {
+ menuItem = _bottomView.Menu.FindItem(index);
+ }
- var menuItem = _bottomView.Menu.FindItem(index);
- UpdateShellSectionEnabled(content, menuItem);
- }
- else if (e.PropertyName == BaseShellItem.TitleProperty.PropertyName ||
- e.PropertyName == BaseShellItem.IconProperty.PropertyName)
- {
- SetupMenu();
+ if (menuItem is not null)
+ {
+ if (e.Is(BaseShellItem.IsEnabledProperty))
+ {
+ UpdateShellSectionEnabled(shellSection, menuItem);
+ }
+ else if (e.Is(BaseShellItem.IconProperty))
+ {
+ _updateMenuItemIcon = menuItem;
+ }
+ else if (e.Is(BaseShellItem.TitleProperty))
+ {
+ _updateMenuItemTitle = menuItem;
+ }
+ }
+
+ // This is primarily used so that `SetupMenu` is still called when the
+ // title and icon property change calls happen. We don't want to break users
+ // that are dependent on that behavior
+ if (e.IsOneOf(BaseShellItem.IconProperty, BaseShellItem.TitleProperty))
+ {
+ try
+ {
+ _updateMenuItemSource = shellSection;
+ SetupMenu();
+ }
+ finally
+ {
+ _updateMenuItemIcon = null;
+ _updateMenuItemTitle = null;
+ _updateMenuItemSource = null;
+ }
+ }
}
}
@@ -406,7 +439,35 @@ protected virtual void OnTabReselected(ShellSection shellSection)
protected virtual void SetupMenu(IMenu menu, int maxBottomItems, ShellItem shellItem)
{
- if (DisplayedPage == null)
+ if ((_updateMenuItemIcon is not null || _updateMenuItemTitle is not null) &&
+ _menuSetup &&
+ _updateMenuItemSource is not null &&
+ _bottomView.IsAlive() &&
+ _bottomView.IsAttachedToWindow)
+ {
+ if (_updateMenuItemIcon is not null)
+ {
+ var menuItem = _updateMenuItemIcon;
+ var shellSection = _updateMenuItemSource;
+ _updateMenuItemSource = null;
+ _updateMenuItemIcon = null;
+
+ UpdateShellSectionIcon(shellSection, menuItem);
+ return;
+ }
+ else if (_updateMenuItemTitle is not null)
+ {
+ var menuItem = _updateMenuItemTitle;
+ var shellSection = _updateMenuItemSource;
+ _updateMenuItemSource = null;
+ _updateMenuItemIcon = null;
+
+ UpdateShellSectionTitle(shellSection, menuItem);
+ return;
+ }
+ }
+
+ if (DisplayedPage is null)
return;
if (ShellItemController.ShowTabs)
@@ -427,6 +488,18 @@ protected virtual void SetupMenu(IMenu menu, int maxBottomItems, ShellItem shell
UpdateTabBarVisibility();
}
+ protected virtual void UpdateShellSectionIcon(ShellSection shellSection, IMenuItem menuItem)
+ {
+ BottomNavigationViewUtils.SetMenuItemIcon(menuItem, shellSection.Icon, MauiContext)
+ .FireAndForget(e => MauiContext?.CreateLogger()?
+ .LogWarning(e, "Failed to Update Shell Section Icon"));
+ }
+
+ protected virtual void UpdateShellSectionTitle(ShellSection shellSection, IMenuItem menuItem)
+ {
+ BottomNavigationViewUtils.SetMenuItemTitle(menuItem, shellSection.Title);
+ }
+
protected virtual void UpdateShellSectionEnabled(ShellSection shellSection, IMenuItem menuItem)
{
bool tabEnabled = shellSection.IsEnabled;
@@ -453,12 +526,12 @@ void SetupMenu()
protected virtual void UpdateTabBarVisibility()
{
- if (DisplayedPage == null)
+ if (DisplayedPage is null)
return;
_bottomView.Visibility = ShellItemController.ShowTabs ? ViewStates.Visible : ViewStates.Gone;
- if (_shellAppearance != null && !_appearanceSet)
+ if (_shellAppearance is not null && !_appearanceSet)
{
SetAppearance(_shellAppearance);
}
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellPageContainer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellPageContainer.cs
index 01402e62d7a1..c58fcf794e9f 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellPageContainer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellPageContainer.cs
@@ -54,6 +54,8 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
aView.Measure(widthMeasureSpec, heightMeasureSpec);
SetMeasuredDimension(aView.MeasuredWidth, aView.MeasuredHeight);
}
+ else
+ SetMeasuredDimension(0, 0);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarAppearanceTracker.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarAppearanceTracker.cs
index 8e8463b22718..1c466efc50ba 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarAppearanceTracker.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarAppearanceTracker.cs
@@ -34,9 +34,17 @@ public virtual void ResetAppearance(AToolbar toolbar, IShellToolbarTracker toolb
protected virtual void SetColors(AToolbar toolbar, IShellToolbarTracker toolbarTracker, Color foreground, Color background, Color title)
{
- _shellContext.Shell.Toolbar.BarTextColor = title ?? ShellRenderer.DefaultTitleColor;
- _shellContext.Shell.Toolbar.BarBackground = new SolidColorBrush(background ?? ShellRenderer.DefaultBackgroundColor);
- _shellContext.Shell.Toolbar.IconColor = foreground ?? ShellRenderer.DefaultForegroundColor;
+ if (_disposed)
+ return;
+
+ Toolbar shellToolbar = _shellContext?.Shell?.Toolbar;
+
+ if (shellToolbar is null)
+ return;
+
+ shellToolbar.BarTextColor = title ?? ShellRenderer.DefaultTitleColor;
+ shellToolbar.BarBackground = new SolidColorBrush(background ?? ShellRenderer.DefaultBackgroundColor);
+ shellToolbar.IconColor = foreground ?? ShellRenderer.DefaultForegroundColor;
}
#region IDisposable
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs
index 852505972c4f..22cf76f5eaad 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs
@@ -77,8 +77,7 @@ public ShellToolbarTracker(IShellContext shellContext, AToolbar toolbar, DrawerL
_drawerLayout = drawerLayout ?? throw new ArgumentNullException(nameof(drawerLayout));
_appBar = _platformToolbar.Parent.GetParentOfType();
- _globalLayoutListener = new GenericGlobalLayoutListener(() => UpdateNavBarHasShadow(Page));
- _appBar.ViewTreeObserver.AddOnGlobalLayoutListener(_globalLayoutListener);
+ _globalLayoutListener = new GenericGlobalLayoutListener((_, _) => UpdateNavBarHasShadow(Page), _appBar);
_platformToolbar.SetNavigationOnClickListener(this);
((IShellController)ShellContext.Shell).AddFlyoutBehaviorObserver(this);
ShellContext.Shell.Toolbar.PropertyChanged += OnToolbarPropertyChanged;
@@ -175,9 +174,6 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- if (_appBar.IsAlive() && _appBar.ViewTreeObserver.IsAlive())
- _appBar.ViewTreeObserver.RemoveOnGlobalLayoutListener(_globalLayoutListener);
-
_globalLayoutListener.Invalidate();
if (_backButtonBehavior != null)
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs
index 4107beb49684..64557f3c39ee 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -551,7 +551,7 @@ public override void WillMoveToSuperview(UIView newSuper)
void UpdateFrame(UIView newSuper)
{
- if (newSuper != null)
+ if (newSuper is not null && newSuper.Bounds != CGRect.Empty)
{
if (!(OperatingSystem.IsIOSVersionAtLeast(11) || OperatingSystem.IsTvOSVersionAtLeast(11)))
Frame = new CGRect(Frame.X, newSuper.Bounds.Y, Frame.Width, newSuper.Bounds.Height);
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRootRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRootRenderer.cs
index 3196afc56722..364dd85fee9b 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRootRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellSectionRootRenderer.cs
@@ -255,7 +255,7 @@ protected virtual void LoadRenderers()
if (item == currentItem)
{
- _containerArea.AddSubview(renderer.PlatformView);
+ _containerArea.AddSubview(renderer.ViewController.View);
_currentContent = currentItem;
_currentIndex = i;
}
diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/UIContainerCell.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/UIContainerCell.cs
index 8eb17591c7c0..37cf75589330 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/UIContainerCell.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/UIContainerCell.cs
@@ -25,7 +25,7 @@ internal UIContainerCell(string cellId, View view, Shell shell, object context)
if (_renderer == null)
{
- _renderer = (IPlatformViewHandler)view.ToHandler(shell.FindMauiContext());
+ _renderer = (IPlatformViewHandler)view.ToHandler(view.FindMauiContext() ?? shell.FindMauiContext());
}
ContentView.AddSubview(_renderer.PlatformView);
diff --git a/src/Controls/src/Core/Compatibility/Handlers/TableView/Tizen/TableViewRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/TableView/Tizen/TableViewRenderer.cs
index 748914a8e7d0..ada7a69c466a 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/TableView/Tizen/TableViewRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/TableView/Tizen/TableViewRenderer.cs
@@ -5,10 +5,10 @@
using Microsoft.Maui.Controls.Handlers.Items;
using Microsoft.Maui.Controls.Platform;
using Tizen.UIExtensions.NUI;
+using IMeasurable = Tizen.UIExtensions.Common.IMeasurable;
using Size = Microsoft.Maui.Graphics.Size;
using TCollectionView = Tizen.UIExtensions.NUI.CollectionView;
using TItemSizingStrategy = Tizen.UIExtensions.NUI.ItemSizingStrategy;
-using IMeasurable = Tizen.UIExtensions.Common.IMeasurable;
using TSize = Tizen.UIExtensions.Common.Size;
namespace Microsoft.Maui.Controls.Handlers.Compatibility
diff --git a/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs
index abd8a233bd24..b343709c5ff6 100644
--- a/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs
+++ b/src/Controls/src/Core/Compatibility/Handlers/VisualElementRenderer.cs
@@ -35,9 +35,11 @@ public abstract partial class VisualElementRenderer : IPlatformViewHan
[nameof(VisualElement.BackgroundColor)] = MapBackgroundColor,
[AutomationProperties.IsInAccessibleTreeProperty.PropertyName] = MapAutomationPropertiesIsInAccessibleTree,
#if WINDOWS
+#pragma warning disable CS0618 // Type or member is obsolete
[AutomationProperties.NameProperty.PropertyName] = MapAutomationPropertiesName,
[AutomationProperties.HelpTextProperty.PropertyName] = MapAutomationPropertiesHelpText,
[AutomationProperties.LabeledByProperty.PropertyName] = MapAutomationPropertiesLabeledBy,
+#pragma warning restore CS0618 // Type or member is obsolete
#endif
};
diff --git a/src/Controls/src/Core/Compatibility/iOS/Extensions/AccessibilityExtensions.cs b/src/Controls/src/Core/Compatibility/iOS/Extensions/AccessibilityExtensions.cs
index 5aa3777918b5..1929392becfb 100644
--- a/src/Controls/src/Core/Compatibility/iOS/Extensions/AccessibilityExtensions.cs
+++ b/src/Controls/src/Core/Compatibility/iOS/Extensions/AccessibilityExtensions.cs
@@ -33,7 +33,9 @@ public static string SetAccessibilityHint(this NativeView Control, Element Eleme
if (_defaultAccessibilityHint == null)
_defaultAccessibilityHint = Control.AccessibilityHint;
+#pragma warning disable CS0618 // Type or member is obsolete
Control.AccessibilityHint = (string)Element.GetValue(AutomationProperties.HelpTextProperty) ?? _defaultAccessibilityHint;
+#pragma warning restore CS0618 // Type or member is obsolete
#else
if (_defaultAccessibilityHint == null)
_defaultAccessibilityHint = Control.AccessibilityTitle;
@@ -52,7 +54,9 @@ public static string SetAccessibilityLabel(this NativeView Control, Element Elem
if (_defaultAccessibilityLabel == null)
_defaultAccessibilityLabel = Control.AccessibilityLabel;
+#pragma warning disable CS0618 // Type or member is obsolete
Control.AccessibilityLabel = (string)Element.GetValue(AutomationProperties.NameProperty) ?? _defaultAccessibilityLabel;
+#pragma warning restore CS0618 // Type or member is obsolete
return _defaultAccessibilityLabel;
}
@@ -66,7 +70,9 @@ public static string SetAccessibilityHint(this UIBarItem Control, Element Elemen
if (_defaultAccessibilityHint == null)
_defaultAccessibilityHint = Control.AccessibilityHint;
+#pragma warning disable CS0618 // Type or member is obsolete
Control.AccessibilityHint = (string)Element.GetValue(AutomationProperties.HelpTextProperty) ?? _defaultAccessibilityHint;
+#pragma warning restore CS0618 // Type or member is obsolete
return _defaultAccessibilityHint;
@@ -80,7 +86,9 @@ public static string SetAccessibilityLabel(this UIBarItem Control, Element Eleme
if (_defaultAccessibilityLabel == null)
_defaultAccessibilityLabel = Control.AccessibilityLabel;
+#pragma warning disable CS0618 // Type or member is obsolete
Control.AccessibilityLabel = (string)Element.GetValue(AutomationProperties.NameProperty) ?? _defaultAccessibilityLabel;
+#pragma warning restore CS0618 // Type or member is obsolete
return _defaultAccessibilityLabel;
}
diff --git a/src/Controls/src/Core/Compatibility/iOS/Extensions/ToolbarItemExtensions.cs b/src/Controls/src/Core/Compatibility/iOS/Extensions/ToolbarItemExtensions.cs
index 0a27731f2c4f..8a099bd2d06f 100644
--- a/src/Controls/src/Core/Compatibility/iOS/Extensions/ToolbarItemExtensions.cs
+++ b/src/Controls/src/Core/Compatibility/iOS/Extensions/ToolbarItemExtensions.cs
@@ -75,10 +75,12 @@ void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
UpdateTextAndStyle();
}
}
+#pragma warning disable CS0618 // Type or member is obsolete
else if (e.PropertyName == AutomationProperties.HelpTextProperty.PropertyName)
this.SetAccessibilityHint(_item);
else if (e.PropertyName == AutomationProperties.NameProperty.PropertyName)
this.SetAccessibilityLabel(_item);
+#pragma warning restore CS0618 // Type or member is obsolete
}
void UpdateIconAndStyle()
@@ -149,9 +151,11 @@ void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
UpdateIcon();
else if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName)
UpdateIsEnabled();
+#pragma warning disable CS0618 // Type or member is obsolete
else if (e.PropertyName == AutomationProperties.HelpTextProperty.PropertyName)
this.SetAccessibilityHint(_item);
else if (e.PropertyName == AutomationProperties.NameProperty.PropertyName)
+#pragma warning restore CS0618 // Type or member is obsolete
this.SetAccessibilityLabel(_item);
}
diff --git a/src/Controls/src/Core/ContentView.cs b/src/Controls/src/Core/ContentView.cs
index cf3b52edbe92..fd81869beec3 100644
--- a/src/Controls/src/Core/ContentView.cs
+++ b/src/Controls/src/Core/ContentView.cs
@@ -22,12 +22,15 @@ protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
- View content = Content;
+ IView content = Content;
+
+ if (content == null && (this as IContentView)?.PresentedContent is IView presentedContent)
+ content = presentedContent;
+
ControlTemplate controlTemplate = ControlTemplate;
- if (content != null && controlTemplate != null)
- {
- SetInheritedBindingContext(content, BindingContext);
- }
+
+ if (content is BindableObject bindableContent && controlTemplate != null)
+ SetInheritedBindingContext(bindableContent, BindingContext);
}
internal override void OnControlTemplateChanged(ControlTemplate oldValue, ControlTemplate newValue)
diff --git a/src/Controls/src/Core/Controls.Core.csproj b/src/Controls/src/Core/Controls.Core.csproj
index aeb6d61141ed..7d4320035e95 100644
--- a/src/Controls/src/Core/Controls.Core.csproj
+++ b/src/Controls/src/Core/Controls.Core.csproj
@@ -1,10 +1,12 @@
+
netstandard2.1;netstandard2.0;$(_MauiDotNetTfm);$(MauiPlatforms)
Microsoft.Maui.Controls
Microsoft.Maui.Controls
+ Microsoft.Maui.Controls.Core
enable
- false
+ true
false
<_MauiDesignDllBuild Condition=" '$(OS)' != 'Unix' ">True
high
@@ -14,7 +16,7 @@
$(NoWarn);CA1420
-
+
@@ -26,6 +28,10 @@
+
+
+
+
@@ -41,11 +47,11 @@
$(TargetsForTfmSpecificBuildOutput);
- _MauiPackXamlDesignAssemblies
+ _MauiPackDesignAssemblies
-
+
Design\Microsoft.Maui.Controls.DesignTools.dll
@@ -56,6 +62,8 @@
+
+
diff --git a/src/Controls/src/Core/Device.cs b/src/Controls/src/Core/Device.cs
index 2e5783525627..2bea4df3c3a4 100644
--- a/src/Controls/src/Core/Device.cs
+++ b/src/Controls/src/Core/Device.cs
@@ -48,27 +48,6 @@ public static class Device
[Obsolete("Use Microsoft.Maui.Devices.DevicePlatform.tvOS instead.")]
public const string tvOS = "tvOS";
- ///
- [Obsolete("Use Microsoft.Maui.Devices.DeviceInfo.Idiom instead.")]
- public static TargetIdiom Idiom
- {
- get
- {
- var idiom = DeviceInfo.Idiom;
- if (idiom == DeviceIdiom.Tablet)
- return TargetIdiom.Tablet;
- if (idiom == DeviceIdiom.Phone)
- return TargetIdiom.Phone;
- if (idiom == DeviceIdiom.Desktop)
- return TargetIdiom.Desktop;
- if (idiom == DeviceIdiom.TV)
- return TargetIdiom.TV;
- if (idiom == DeviceIdiom.Watch)
- return TargetIdiom.Watch;
- return TargetIdiom.Unsupported;
- }
- }
-
///
[Obsolete("Use Microsoft.Maui.Devices.DeviceInfo.Platform instead.")]
public static string RuntimePlatform => DeviceInfo.Platform.ToString();
diff --git a/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs b/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs
index 37311146584c..f7edda731a9d 100644
--- a/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs
+++ b/src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs
@@ -76,7 +76,7 @@ internal void RemoveWindow(Window window)
if (window is Element windowElement)
{
var oldIndex = InternalChildren.IndexOf(windowElement);
- InternalChildren.Remove(windowElement);
+ InternalChildren.RemoveAt(oldIndex);
windowElement.Parent = null;
OnChildRemoved(windowElement, oldIndex);
}
diff --git a/src/Controls/src/Core/HandlerImpl/Label/Label.Tizen.cs b/src/Controls/src/Core/HandlerImpl/Label/Label.Tizen.cs
index 8907ea8c1cf6..2150ad58740a 100644
--- a/src/Controls/src/Core/HandlerImpl/Label/Label.Tizen.cs
+++ b/src/Controls/src/Core/HandlerImpl/Label/Label.Tizen.cs
@@ -1,7 +1,7 @@
#nullable disable
using Microsoft.Maui;
-using Microsoft.Maui.Handlers;
using Microsoft.Maui.Controls.Platform;
+using Microsoft.Maui.Handlers;
namespace Microsoft.Maui.Controls
{
diff --git a/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs b/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs
index d0c45a7b042d..6b92d1609f61 100644
--- a/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs
+++ b/src/Controls/src/Core/HandlerImpl/NavigationPage/NavigationPage.Impl.cs
@@ -181,32 +181,36 @@ async Task SendHandlerUpdateAsync(
// Wait for pending navigation tasks to finish
await SemaphoreSlim.WaitAsync();
- var currentNavRequestTaskSource = new TaskCompletionSource
@@ -31,10 +32,6 @@
-
-
-
-
@@ -45,9 +42,6 @@
True
MauiGResources.resx
-
-
-
ResXFileCodeGenerator
MauiGResources.Designer.cs
@@ -58,8 +52,13 @@
-
-
+
+
+
+ <_CopyItems Include="$(TargetDir)*.dll" Exclude="$(TargetDir)System.*.dll" />
+ <_CopyItems Include="$(TargetDir)*.pdb" Exclude="$(TargetDir)System.*.pdb" />
+
+
diff --git a/src/Controls/src/Xaml.Design/Controls.Xaml.Design.csproj b/src/Controls/src/Xaml.Design/Controls.Xaml.Design.csproj
index 47c415798e3a..095b3456c6d3 100644
--- a/src/Controls/src/Xaml.Design/Controls.Xaml.Design.csproj
+++ b/src/Controls/src/Xaml.Design/Controls.Xaml.Design.csproj
@@ -12,8 +12,6 @@
-
- 17.4.33103.184
-
+
\ No newline at end of file
diff --git a/src/Controls/src/Xaml/Controls.Xaml.csproj b/src/Controls/src/Xaml/Controls.Xaml.csproj
index 707ac8830adb..fdbdb523d462 100644
--- a/src/Controls/src/Xaml/Controls.Xaml.csproj
+++ b/src/Controls/src/Xaml/Controls.Xaml.csproj
@@ -4,7 +4,7 @@
netstandard2.1;netstandard2.0;$(_MauiDotNetTfm);$(MauiPlatforms)
Microsoft.Maui.Controls.Xaml
Microsoft.Maui.Controls.Xaml
- false
+ true
false
<_MauiDesignDllBuild Condition=" '$(OS)' != 'Unix' ">True
$(NoWarn);CA2200;CS1591;RS0041
@@ -18,22 +18,26 @@
-
+
+
+
+
+
-
- $(TargetsForTfmSpecificBuildOutput);
- _MauiPackXamlDesignAssemblies
-
+
+ $(TargetsForTfmSpecificBuildOutput);
+ _MauiPackDesignAssemblies
+
-
+
Design\Microsoft.Maui.Controls.Xaml.DesignTools.dll
@@ -44,6 +48,8 @@
+
+
diff --git a/src/Controls/src/Xaml/TypeArgumentsParser.cs b/src/Controls/src/Xaml/TypeArgumentsParser.cs
index 4fc536ba210b..7e730ca6f33d 100644
--- a/src/Controls/src/Xaml/TypeArgumentsParser.cs
+++ b/src/Controls/src/Xaml/TypeArgumentsParser.cs
@@ -45,9 +45,10 @@ static XmlType Parse(string match, ref string remaining, IXmlNamespaceResolver r
IList typeArguments = null;
if (isGeneric)
{
+ var openBracket = type.IndexOf("(", StringComparison.Ordinal);
typeArguments = ParseExpression(
- type.Substring(type.IndexOf("(", StringComparison.Ordinal) + 1, type.LastIndexOf(")", StringComparison.Ordinal) - type.IndexOf("(", StringComparison.Ordinal) - 1), resolver, lineinfo);
- type = type.Substring(0, type.IndexOf("(", StringComparison.Ordinal));
+ type.Substring(openBracket + 1, type.LastIndexOf(")", StringComparison.Ordinal) - openBracket - 1), resolver, lineinfo);
+ type = type.Substring(0, openBracket);
}
var split = type.Split(':');
diff --git a/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs b/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs
index 9c823998fee0..6fb90ee8bd41 100644
--- a/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs
+++ b/src/Controls/src/Xaml/XmlTypeXamlExtensions.cs
@@ -68,8 +68,9 @@ static class XmlTypeXamlExtensions
for (var i = 0; i < lookupNames.Count; i++)
{
var name = lookupNames[i];
- if (name.IndexOf(":", StringComparison.Ordinal) != -1)
- name = name.Substring(name.LastIndexOf(':') + 1);
+ var lastIndex = name.LastIndexOf(":", StringComparison.Ordinal);
+ if (lastIndex != -1)
+ name = name.Substring(lastIndex + 1);
if (typeArguments != null)
name += "`" + typeArguments.Count; //this will return an open generic Type
lookupNames[i] = name;
diff --git a/src/Controls/tests/Core.UnitTests/AcceleratorUnitTests.cs b/src/Controls/tests/Core.UnitTests/AcceleratorUnitTests.cs
index 871d5199a216..5b55e5f6e376 100644
--- a/src/Controls/tests/Core.UnitTests/AcceleratorUnitTests.cs
+++ b/src/Controls/tests/Core.UnitTests/AcceleratorUnitTests.cs
@@ -73,7 +73,9 @@ public void AcceleratorFromLetterAnd2Modifier()
[Preserve(AllMembers = true)]
+#pragma warning disable CA1815 // Override equals and operator equals on value types
public struct TestShortcut
+#pragma warning restore CA1815 // Override equals and operator equals on value types
{
internal TestShortcut(string modifier)
{
diff --git a/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs b/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs
index 39c17e1bca30..b9367d383c38 100644
--- a/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs
+++ b/src/Controls/tests/Core.UnitTests/BindingUnitTests.cs
@@ -1,8 +1,10 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xunit;
@@ -1185,6 +1187,81 @@ public void ValueUpdatedWithSelfPathOnTwoWayBinding(bool isDefault)
AssertNoErrorsLogged();
}
+
+ [Theory, Category("[Binding] Complex paths")]
+ [InlineData(BindingMode.OneWay)]
+ [InlineData(BindingMode.OneWayToSource)]
+ [InlineData(BindingMode.TwoWay)]
+ public async Task WeakPropertyChangedProxyDoesNotLeak(BindingMode mode)
+ {
+ var proxies = new List();
+ WeakReference weakViewModel = null, weakBindable = null;
+
+ int i = 0;
+ void create()
+ {
+ if (i++ < 1024)
+ {
+ create();
+ return;
+ }
+
+ var binding = new Binding("Model.Model[1]");
+ var bindable = new MockBindable();
+ weakBindable = new WeakReference(bindable);
+
+ var viewmodel = new ComplexMockViewModel
+ {
+ Model = new ComplexMockViewModel
+ {
+ Model = new ComplexMockViewModel()
+ }
+ };
+
+ weakViewModel = new WeakReference(viewmodel);
+
+ bindable.BindingContext = viewmodel;
+ bindable.SetBinding(MockBindable.TextProperty, binding);
+
+ // Access private members:
+ // WeakPropertyChangedProxy proxy = binding._expression._parts[i]._listener;
+ var flags = BindingFlags.NonPublic | BindingFlags.Instance;
+ var expression = binding.GetType().GetField("_expression", flags).GetValue(binding);
+ Assert.NotNull(expression);
+ var parts = expression.GetType().GetField("_parts", flags).GetValue(expression) as IEnumerable;
+ Assert.NotNull(parts);
+ foreach (var part in parts)
+ {
+ var listener = part.GetType().GetField("_listener", flags).GetValue(part);
+ if (listener == null)
+ continue;
+ proxies.Add(new WeakReference(listener));
+ }
+ Assert.NotEmpty(proxies); // Should be at least 1
+ };
+ create();
+
+ await Task.Yield();
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+
+ if (mode == BindingMode.TwoWay || mode == BindingMode.OneWay)
+ Assert.False(weakViewModel.IsAlive, "ViewModel wasn't collected");
+
+ if (mode == BindingMode.TwoWay || mode == BindingMode.OneWayToSource)
+ Assert.False(weakBindable.IsAlive, "Bindable wasn't collected");
+
+ // WeakPropertyChangedProxy won't go away until the second GC, BindingExpressionPart unsubscribes in its finalizer
+ await Task.Yield();
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+
+ foreach (var proxy in proxies)
+ {
+ Assert.False(proxy.IsAlive, "WeakPropertyChangedProxy wasn't collected");
+ }
+ }
+
[Theory, Category("[Binding] Complex paths")]
[InlineData(BindingMode.OneWay)]
[InlineData(BindingMode.OneWayToSource)]
diff --git a/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj b/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj
index 68362d181fad..08cdf415936b 100644
--- a/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj
+++ b/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj
@@ -15,7 +15,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/src/Controls/tests/Core.UnitTests/Layouts/FlexLayoutTests.cs b/src/Controls/tests/Core.UnitTests/Layouts/FlexLayoutTests.cs
index 6194eff0ea01..15934ee07889 100644
--- a/src/Controls/tests/Core.UnitTests/Layouts/FlexLayoutTests.cs
+++ b/src/Controls/tests/Core.UnitTests/Layouts/FlexLayoutTests.cs
@@ -1,5 +1,6 @@
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Layouts;
+using NSubstitute;
using Xunit;
namespace Microsoft.Maui.Controls.Core.UnitTests.Layouts
@@ -80,5 +81,53 @@ public void FlexLayoutRecognizesVisibilityChange()
// now that the first view is not visible
Assert.True(whenInvisible != whenVisible);
}
+
+ /*
+ * These next two tests deal with unconstrained measure of FlexLayout. Be default, FL
+ * wants to stretch children across each axis. But you can't stretch things across infinity
+ * without it getting weird. So for _measurement_ purposes, we treat infinity as zero and
+ * just give the children their desired size in the unconstrained direction. Otherwise, FL
+ * would just set their flex frame sizes to zero, which can either cause blanks or layout cycles,
+ * depending on the target platform.
+ */
+
+ (IFlexLayout, IView) SetUpUnconstrainedTest()
+ {
+ var root = new Grid(); // FlexLayout requires a parent, at least for now
+ var flexLayout = new FlexLayout() as IFlexLayout;
+
+ var view = Substitute.For();
+ var size = new Size(100, 100);
+ view.Measure(Arg.Any(), Arg.Any()).Returns(size);
+
+ root.Add(flexLayout);
+ flexLayout.Add(view);
+
+ return (flexLayout, view);
+ }
+
+ [Fact]
+ public void UnconstrainedHeightChildrenHaveHeight()
+ {
+ (var flexLayout, var view) = SetUpUnconstrainedTest();
+
+ _ = flexLayout.CrossPlatformMeasure(400, double.PositiveInfinity);
+
+ var flexFrame = flexLayout.GetFlexFrame(view);
+
+ Assert.Equal(100, flexFrame.Height);
+ }
+
+ [Fact]
+ public void UnconstrainedWidthChildrenHaveWidth()
+ {
+ (var flexLayout, var view) = SetUpUnconstrainedTest();
+
+ _ = flexLayout.CrossPlatformMeasure(double.PositiveInfinity, 400);
+
+ var flexFrame = flexLayout.GetFlexFrame(view);
+
+ Assert.Equal(100, flexFrame.Width);
+ }
}
}
diff --git a/src/Controls/tests/Core.UnitTests/NavigationUnitTest.cs b/src/Controls/tests/Core.UnitTests/NavigationUnitTest.cs
index 53e9c4e35c30..c5e1d41a81bd 100644
--- a/src/Controls/tests/Core.UnitTests/NavigationUnitTest.cs
+++ b/src/Controls/tests/Core.UnitTests/NavigationUnitTest.cs
@@ -21,6 +21,24 @@ public async Task HandlerUpdatesDontFireForLegacy(bool withPage)
var handler = new TestNavigationHandler();
(nav as IView).Handler = handler;
+ Assert.Null(nav.CurrentNavigationTask);
+ Assert.Null(handler.CurrentNavigationRequest);
+ }
+
+ [Fact]
+ public async Task NavigationInLimboCompletesWhenHandlerIsRemoved()
+ {
+ TestNavigationPage nav =
+ new TestNavigationPage(true);
+
+ var task = nav.PushAsync(new ContentPage());
+ (nav as IView).Handler = null;
+ await task.WaitAsync(TimeSpan.FromMilliseconds(100));
+
+ var handler = new TestNavigationHandler();
+ (nav as IView).Handler = handler;
+
+ await nav.PushAsync(new ContentPage());
Assert.Null(nav.CurrentNavigationTask);
Assert.Null(handler.CurrentNavigationRequest);
diff --git a/src/Controls/tests/Core.UnitTests/NotifiedPropertiesTests.cs b/src/Controls/tests/Core.UnitTests/NotifiedPropertiesTests.cs
index 02adc4d0ca2f..4ee4088e2c37 100644
--- a/src/Controls/tests/Core.UnitTests/NotifiedPropertiesTests.cs
+++ b/src/Controls/tests/Core.UnitTests/NotifiedPropertiesTests.cs
@@ -117,7 +117,6 @@ public override string DebugName
new PropertyTestCase
+
+
+
+
+
+
+
+
+
+ & '$(DotNetInstallScriptPath)' -Version $(VersionFromAndroid) -InstallDir '$(DotNetDirectory)' -Verbose -Runtime dotnet
+ & '$(DotNetInstallScriptPath)' -Version $(VersionFromMacios) -InstallDir '$(DotNetDirectory)' -Verbose -Runtime dotnet
+ powershell -ExecutionPolicy ByPass -NoProfile -Command "$(DotNetXARuntimeInstallCommand)"
+ powershell -ExecutionPolicy ByPass -NoProfile -Command "$(DotNetXMRuntimeInstallCommand)"
+
+
+ bash '$(DotNetInstallScriptPath)' --version $(VersionFromAndroid) --install-dir '$(DotNetDirectory)' --verbose -Runtime dotnet
+ bash '$(DotNetInstallScriptPath)' --version $(VersionFromMacios) --install-dir '$(DotNetDirectory)' --verbose -Runtime dotnet
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Essentials/docs/frameworks.xml b/src/Essentials/docs/frameworks.xml
deleted file mode 100644
index 26b6ec3981fe..000000000000
--- a/src/Essentials/docs/frameworks.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/src/Essentials/samples/Samples/Essentials.Sample.csproj b/src/Essentials/samples/Samples/Essentials.Sample.csproj
index a8b4f2d98c87..ed5ca90f2524 100644
--- a/src/Essentials/samples/Samples/Essentials.Sample.csproj
+++ b/src/Essentials/samples/Samples/Essentials.Sample.csproj
@@ -8,6 +8,8 @@
true
false
$(NoWarn),CA1416
+
+ maccatalyst-x64
diff --git a/src/Essentials/samples/Samples/View/GeolocationPage.xaml b/src/Essentials/samples/Samples/View/GeolocationPage.xaml
index c10eeb38c638..67475e119435 100644
--- a/src/Essentials/samples/Samples/View/GeolocationPage.xaml
+++ b/src/Essentials/samples/Samples/View/GeolocationPage.xaml
@@ -27,6 +27,16 @@
IsEnabled="{Binding IsNotBusy}"
HorizontalOptions="FillAndExpand" />
+
+
+
+
+
+
+
+
diff --git a/src/Essentials/samples/Samples/ViewModel/GeolocationViewModel.cs b/src/Essentials/samples/Samples/ViewModel/GeolocationViewModel.cs
index 9a937ee239c6..ed9d3c0275f4 100644
--- a/src/Essentials/samples/Samples/ViewModel/GeolocationViewModel.cs
+++ b/src/Essentials/samples/Samples/ViewModel/GeolocationViewModel.cs
@@ -13,17 +13,25 @@ public class GeolocationViewModel : BaseViewModel
string currentLocation;
int accuracy = (int)GeolocationAccuracy.Default;
CancellationTokenSource cts;
+ string listeningLocation;
+ string listeningLocationStatus;
public GeolocationViewModel()
{
GetLastLocationCommand = new Command(OnGetLastLocation);
GetCurrentLocationCommand = new Command(OnGetCurrentLocation);
+ StartListeningCommand = new Command(OnStartListening);
+ StopListeningCommand = new Command(OnStopListening);
}
public ICommand GetLastLocationCommand { get; }
public ICommand GetCurrentLocationCommand { get; }
+ public ICommand StartListeningCommand { get; }
+
+ public ICommand StopListeningCommand { get; }
+
public string LastLocation
{
get => lastLocation;
@@ -45,6 +53,22 @@ public int Accuracy
set => SetProperty(ref accuracy, value);
}
+ public bool IsListening => Geolocation.IsListeningForeground;
+
+ public bool IsNotListening => !IsListening;
+
+ public string ListeningLocation
+ {
+ get => listeningLocation;
+ set => SetProperty(ref listeningLocation, value);
+ }
+
+ public string ListeningLocationStatus
+ {
+ get => listeningLocationStatus;
+ set => SetProperty(ref listeningLocationStatus, value);
+ }
+
async void OnGetLastLocation()
{
if (IsBusy)
@@ -88,6 +112,53 @@ async void OnGetCurrentLocation()
IsBusy = false;
}
+ async void OnStartListening()
+ {
+ try
+ {
+ Geolocation.LocationChanged += Geolocation_LocationChanged;
+
+ var request = new GeolocationListeningRequest((GeolocationAccuracy)Accuracy);
+
+ var success = await Geolocation.StartListeningForegroundAsync(request);
+
+ ListeningLocationStatus = success
+ ? "Started listening for foreground location updates"
+ : "Couldn't start listening";
+ }
+ catch (Exception ex)
+ {
+ ListeningLocationStatus = FormatLocation(null, ex);
+ }
+
+ OnPropertyChanged(nameof(IsListening));
+ OnPropertyChanged(nameof(IsNotListening));
+ }
+
+ void Geolocation_LocationChanged(object sender, GeolocationLocationChangedEventArgs e)
+ {
+ ListeningLocation = FormatLocation(e.Location);
+ }
+
+ void OnStopListening()
+ {
+ try
+ {
+ Geolocation.LocationChanged -= Geolocation_LocationChanged;
+
+ Geolocation.StopListeningForeground();
+
+ ListeningLocationStatus = "Stopped listening for foreground location updates";
+ }
+ catch (Exception ex)
+ {
+ ListeningLocationStatus = FormatLocation(null, ex);
+ }
+
+ OnPropertyChanged(nameof(IsListening));
+ OnPropertyChanged(nameof(IsNotListening));
+ }
+
string FormatLocation(Location location, Exception ex = null)
{
if (location == null)
@@ -116,6 +187,9 @@ public override void OnDisappearing()
if (cts != null && !cts.IsCancellationRequested)
cts.Cancel();
}
+
+ OnStopListening();
+
base.OnDisappearing();
}
}
diff --git a/src/Essentials/src/Accelerometer/Accelerometer.shared.cs b/src/Essentials/src/Accelerometer/Accelerometer.shared.cs
index b6289337a05f..e4b6424b2b06 100644
--- a/src/Essentials/src/Accelerometer/Accelerometer.shared.cs
+++ b/src/Essentials/src/Accelerometer/Accelerometer.shared.cs
@@ -150,6 +150,7 @@ public AccelerometerData(float x, float y, float z) =>
///
public Vector3 Acceleration { get; }
+ ///
public override bool Equals(object? obj) =>
(obj is AccelerometerData data) && Equals(data);
@@ -179,6 +180,7 @@ public bool Equals(AccelerometerData other) =>
public static bool operator !=(AccelerometerData left, AccelerometerData right) =>
!left.Equals(right);
+ ///
public override int GetHashCode() =>
Acceleration.GetHashCode();
diff --git a/src/Essentials/src/Barometer/Barometer.shared.cs b/src/Essentials/src/Barometer/Barometer.shared.cs
index 7e0c9f267457..16bd693db8ed 100644
--- a/src/Essentials/src/Barometer/Barometer.shared.cs
+++ b/src/Essentials/src/Barometer/Barometer.shared.cs
@@ -159,6 +159,7 @@ public override bool Equals(object? obj) =>
public bool Equals(BarometerData other) =>
PressureInHectopascals.Equals(other.PressureInHectopascals);
+ ///
public override int GetHashCode() =>
PressureInHectopascals.GetHashCode();
diff --git a/src/Essentials/src/Compass/Compass.shared.cs b/src/Essentials/src/Compass/Compass.shared.cs
index 996718695ad0..daa3cc590824 100644
--- a/src/Essentials/src/Compass/Compass.shared.cs
+++ b/src/Essentials/src/Compass/Compass.shared.cs
@@ -44,11 +44,14 @@ public interface ICompass
}
///
- /// Platform-specific APIs for use with
+ /// Platform-specific APIs for use with .
///
public interface IPlatformCompass
{
#if IOS || MACCATALYST
+ ///
+ /// Gets or sets if heading calibration should be shown.
+ ///
bool ShouldDisplayHeadingCalibration { get; set; }
#endif
}
@@ -144,7 +147,7 @@ internal static void SetDefault(ICompass? implementation) =>
}
///
- /// /// This class contains static extension methods for use with .
+ /// This class contains static extension methods for use with .
///
public static class CompassExtensions
{
@@ -232,6 +235,7 @@ public bool Equals(CompassData other) =>
public static bool operator !=(CompassData left, CompassData right) =>
!left.Equals(right);
+ ///
public override int GetHashCode() =>
HeadingMagneticNorth.GetHashCode();
diff --git a/src/Essentials/src/Contacts/Contacts.android.cs b/src/Essentials/src/Contacts/Contacts.android.cs
index 5f1cd535ea4b..814f4ce4b7cf 100644
--- a/src/Essentials/src/Contacts/Contacts.android.cs
+++ b/src/Essentials/src/Contacts/Contacts.android.cs
@@ -120,12 +120,16 @@ static IEnumerable ReadCursorItems(ICursor cursor, string dataKey)
if (cursor?.MoveToFirst() != true)
return (null, null, null, null, null);
- return (
+ var result = (
GetString(cursor, StructuredName.Prefix),
GetString(cursor, StructuredName.GivenName),
GetString(cursor, StructuredName.MiddleName),
GetString(cursor, StructuredName.FamilyName),
GetString(cursor, StructuredName.Suffix));
+
+ cursor?.Close();
+
+ return result;
}
static string GetString(ICursor cursor, string column) =>
diff --git a/src/Essentials/src/Essentials.csproj b/src/Essentials/src/Essentials.csproj
index 128689c60c8d..e667f8b42332 100644
--- a/src/Essentials/src/Essentials.csproj
+++ b/src/Essentials/src/Essentials.csproj
@@ -5,20 +5,18 @@
Microsoft.Maui.Essentials
false
BI1234
- false
+ true
true
true
- $(NoWarn);CS1591;NU5104;RS0041;RS0026
+ $(NoWarn);NU5104;RS0041;RS0026
+ $(WarningsAsErrors);CS1591
$(NoWarn);CA1420
-
+
-
-
-
@@ -67,4 +65,5 @@
-->
+
diff --git a/src/Essentials/src/FilePicker/FilePicker.shared.cs b/src/Essentials/src/FilePicker/FilePicker.shared.cs
index 7e7c4bac937e..a0a32d00b98b 100644
--- a/src/Essentials/src/FilePicker/FilePicker.shared.cs
+++ b/src/Essentials/src/FilePicker/FilePicker.shared.cs
@@ -133,6 +133,9 @@ public partial class FilePickerFileType
readonly IDictionary> fileTypes;
+ ///
+ /// Initializes a new instance of the class.
+ ///
protected FilePickerFileType() =>
fileTypes = new Dictionary>();
@@ -154,6 +157,10 @@ public FilePickerFileType(IDictionary> fileT
/// Thrown if the current platform does not have any file types configured.
public IEnumerable Value => GetPlatformFileType(DeviceInfo.Current.Platform);
+ ///
+ /// Gets the configured allowed file types that can be picked by the user for the current platform.
+ ///
+ /// Thrown if the current platform does not have any file types configured.
protected virtual IEnumerable GetPlatformFileType(DevicePlatform platform)
{
if (fileTypes.TryGetValue(platform, out var type))
diff --git a/src/Essentials/src/FileSystem/FileSystem.shared.cs b/src/Essentials/src/FileSystem/FileSystem.shared.cs
index a1a99535d5c8..6461323cd3be 100644
--- a/src/Essentials/src/FileSystem/FileSystem.shared.cs
+++ b/src/Essentials/src/FileSystem/FileSystem.shared.cs
@@ -67,7 +67,7 @@ public static Task OpenAppPackageFileAsync(string filename)
///
/// Determines whether or not a file exists in the app package.
///
- /// The name of the file (excluding the path) to load from the app package.
+ /// The path of the file (relative to the app package) to check the existence of.
/// when the specified file exists in the app package, otherwise .
public static Task AppPackageFileExistsAsync(string filename)
=> Current.AppPackageFileExistsAsync(filename);
@@ -89,15 +89,19 @@ internal static void SetCurrent(IFileSystem? implementation) =>
///
public partial class FileSystemImplementation
{
+ ///
public string CacheDirectory
=> PlatformCacheDirectory;
+ ///
public string AppDataDirectory
=> PlatformAppDataDirectory;
+ ///
public Task OpenAppPackageFileAsync(string filename)
=> PlatformOpenAppPackageFileAsync(filename);
+ ///
public Task AppPackageFileExistsAsync(string filename)
=> PlatformAppPackageFileExistsAsync(filename);
}
diff --git a/src/Essentials/src/Geolocation/Geolocation.android.cs b/src/Essentials/src/Geolocation/Geolocation.android.cs
index f2f8454efd21..b7035227b163 100644
--- a/src/Essentials/src/Geolocation/Geolocation.android.cs
+++ b/src/Essentials/src/Geolocation/Geolocation.android.cs
@@ -18,11 +18,19 @@ partial class GeolocationImplementation : IGeolocation
const long twoMinutes = 120000;
static readonly string[] ignoredProviders = new string[] { LocationManager.PassiveProvider, "local_database" };
+ static ContinuousLocationListener continuousListener;
+ static List listeningProviders;
+
static LocationManager locationManager;
static LocationManager LocationManager =>
locationManager ??= Application.Context.GetSystemService(Context.LocationService) as LocationManager;
+ ///
+ /// Indicates if currently listening to location updates while the app is in foreground.
+ ///
+ public bool IsListeningForeground { get => continuousListener != null; }
+
public async Task GetLastKnownLocationAsync()
{
await Permissions.EnsureGrantedOrRestrictedAsync();
@@ -42,7 +50,7 @@ public async Task GetLastKnownLocationAsync()
public async Task GetLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
{
- _ = request ?? throw new ArgumentNullException(nameof(request));
+ ArgumentNullException.ThrowIfNull(request);
await Permissions.EnsureGrantedOrRestrictedAsync();
@@ -112,6 +120,101 @@ void RemoveUpdates()
}
}
+ ///
+ /// Starts listening to location updates using the
+ /// event or the event. Events may only sent when
+ /// the app is in the foreground. Requests
+ /// from the user.
+ ///
+ /// Thrown when is .
+ /// Thrown if listening is not supported on this platform.
+ /// Thrown if already listening and returns .
+ /// The listening request parameters to use.
+ /// when listening was started, or when listening couldn't be started.
+ public async Task StartListeningForegroundAsync(GeolocationListeningRequest request)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+
+ if (IsListeningForeground)
+ throw new InvalidOperationException("Already listening to location changes.");
+
+ await Permissions.EnsureGrantedOrRestrictedAsync();
+
+ var enabledProviders = LocationManager.GetProviders(true);
+ var hasProviders = enabledProviders.Any(p => !ignoredProviders.Contains(p));
+
+ if (!hasProviders)
+ throw new FeatureNotEnabledException("Location services are not enabled on device.");
+
+ // get the best possible provider for the requested accuracy
+ var providerInfo = GetBestProvider(LocationManager, request.DesiredAccuracy);
+
+ // if no providers exist, we can't listen for locations
+ if (string.IsNullOrEmpty(providerInfo.Provider))
+ return false;
+
+ var allProviders = LocationManager.GetProviders(false);
+
+ listeningProviders = new List();
+ if (allProviders.Contains(Android.Locations.LocationManager.GpsProvider))
+ listeningProviders.Add(Android.Locations.LocationManager.GpsProvider);
+ if (allProviders.Contains(Android.Locations.LocationManager.NetworkProvider))
+ listeningProviders.Add(Android.Locations.LocationManager.NetworkProvider);
+
+ if (listeningProviders.Count == 0)
+ listeningProviders.Add(providerInfo.Provider);
+
+ var continuousListener = new ContinuousLocationListener(LocationManager, providerInfo.Accuracy, listeningProviders);
+ continuousListener.LocationHandler = HandleLocation;
+ continuousListener.ErrorHandler = HandleError;
+
+ // start getting location updates
+ // make sure to use a thread with a looper
+ var looper = Looper.MyLooper() ?? Looper.MainLooper;
+
+ var minTimeMilliseconds = (long)request.MinimumTime.TotalMilliseconds;
+
+ foreach (var provider in listeningProviders)
+ LocationManager.RequestLocationUpdates(provider, minTimeMilliseconds, providerInfo.Accuracy, continuousListener, looper);
+
+ return true;
+
+ void HandleLocation(AndroidLocation location)
+ {
+ OnLocationChanged(location.ToLocation());
+ }
+
+ void HandleError(GeolocationError geolocationError)
+ {
+ StopListeningForeground();
+ OnLocationError(geolocationError);
+ }
+ }
+
+ ///
+ /// Stop listening for location updates when the app is in the foreground.
+ /// Has no effect when not listening and
+ /// is currently .
+ ///
+ public void StopListeningForeground()
+ {
+ if (continuousListener == null)
+ return;
+
+ continuousListener.LocationHandler = null;
+ continuousListener.ErrorHandler = null;
+
+ if (listeningProviders == null)
+ return;
+
+ for (var i = 0; i < listeningProviders.Count; i++)
+ {
+ LocationManager.RemoveUpdates(continuousListener);
+ }
+
+ continuousListener = null;
+ }
+
static (string Provider, float Accuracy) GetBestProvider(LocationManager locationManager, GeolocationAccuracy accuracy)
{
// Criteria: https://developer.android.com/reference/android/location/Criteria
@@ -276,4 +379,68 @@ void ILocationListener.OnStatusChanged(string provider, Availability status, Bun
}
}
}
+
+ class ContinuousLocationListener : Java.Lang.Object, ILocationListener
+ {
+ readonly LocationManager manager;
+
+ float desiredAccuracy;
+
+ HashSet activeProviders = new HashSet();
+
+ internal Action LocationHandler { get; set; }
+
+ internal Action ErrorHandler { get; set; }
+
+ internal ContinuousLocationListener(LocationManager manager, float desiredAccuracy, IEnumerable providers)
+ {
+ this.manager = manager;
+ this.desiredAccuracy = desiredAccuracy;
+
+ foreach (var provider in providers)
+ {
+ if (manager.IsProviderEnabled(provider))
+ activeProviders.Add(provider);
+ }
+ }
+
+ void ILocationListener.OnLocationChanged(AndroidLocation location)
+ {
+ if (location.Accuracy <= desiredAccuracy)
+ {
+ LocationHandler?.Invoke(location);
+ return;
+ }
+ }
+
+ void ILocationListener.OnProviderDisabled(string provider)
+ {
+ lock (activeProviders)
+ {
+ if (activeProviders.Remove(provider) &&
+ activeProviders.Count == 0)
+ ErrorHandler?.Invoke(GeolocationError.PositionUnavailable);
+ }
+ }
+
+ void ILocationListener.OnProviderEnabled(string provider)
+ {
+ lock (activeProviders)
+ activeProviders.Add(provider);
+ }
+
+ void ILocationListener.OnStatusChanged(string provider, Availability status, Bundle extras)
+ {
+ switch (status)
+ {
+ case Availability.Available:
+ ((ILocationListener)this).OnProviderEnabled(provider);
+ break;
+
+ case Availability.OutOfService:
+ ((ILocationListener)this).OnProviderDisabled(provider);
+ break;
+ }
+ }
+ }
}
diff --git a/src/Essentials/src/Geolocation/Geolocation.ios.macos.cs b/src/Essentials/src/Geolocation/Geolocation.ios.macos.cs
index 3a7ea40794bd..e2c93bace244 100644
--- a/src/Essentials/src/Geolocation/Geolocation.ios.macos.cs
+++ b/src/Essentials/src/Geolocation/Geolocation.ios.macos.cs
@@ -3,12 +3,20 @@
using System.Threading;
using System.Threading.Tasks;
using CoreLocation;
+using Foundation;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
{
partial class GeolocationImplementation : IGeolocation
{
+ CLLocationManager listeningManager;
+
+ ///
+ /// Indicates if currently listening to location updates while the app is in foreground.
+ ///
+ public bool IsListeningForeground { get => listeningManager != null; }
+
public async Task GetLastKnownLocationAsync()
{
if (!CLLocationManager.LocationServicesEnabled)
@@ -31,7 +39,7 @@ public async Task GetLastKnownLocationAsync()
public async Task GetLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
{
- _ = request ?? throw new ArgumentNullException(nameof(request));
+ ArgumentNullException.ThrowIfNull(request);
if (!CLLocationManager.LocationServicesEnabled)
throw new FeatureNotEnabledException("Location services are not enabled on device.");
@@ -91,6 +99,94 @@ void Cancel()
tcs.TrySetResult(null);
}
}
+
+ ///
+ /// Starts listening to location updates using the
+ /// event or the event. Events may only sent when
+ /// the app is in the foreground. Requests
+ /// from the user.
+ ///
+ /// Thrown when is .
+ /// Thrown if listening is not supported on this platform.
+ /// Thrown if already listening and returns .
+ /// The listening request parameters to use.
+ /// when listening was started, or when listening couldn't be started.
+ public async Task StartListeningForegroundAsync(GeolocationListeningRequest request)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+
+ if (IsListeningForeground)
+ throw new InvalidOperationException("Already listening to location changes.");
+
+ if (!CLLocationManager.LocationServicesEnabled)
+ throw new FeatureNotEnabledException("Location services are not enabled on device.");
+
+ await Permissions.EnsureGrantedAsync();
+
+ // the location manager requires an active run loop
+ // so just use the main loop
+ listeningManager = MainThread.InvokeOnMainThread(() => new CLLocationManager());
+
+ var reducedAccuracy = false;
+#if __IOS__
+ if (OperatingSystem.IsIOSVersionAtLeast(14, 0))
+ {
+ reducedAccuracy = listeningManager.AccuracyAuthorization == CLAccuracyAuthorization.ReducedAccuracy;
+ }
+#endif
+
+ var listener = new ContinuousLocationListener();
+ listener.LocationHandler += HandleLocation;
+ listener.ErrorHandler += HandleError;
+
+ listeningManager.DesiredAccuracy = request.PlatformDesiredAccuracy;
+ listeningManager.Delegate = listener;
+
+#if __IOS__
+#pragma warning disable CA1416 // https://github.com/xamarin/xamarin-macios/issues/14619
+ // allow pausing updates
+ listeningManager.PausesLocationUpdatesAutomatically = true;
+#pragma warning restore CA1416
+#endif
+
+ listeningManager.StartUpdatingLocation();
+
+ return true;
+
+ void HandleLocation(CLLocation clLocation)
+ {
+ OnLocationChanged(clLocation?.ToLocation(reducedAccuracy));
+ }
+
+ void HandleError(GeolocationError error)
+ {
+ StopListeningForeground();
+ OnLocationError(error);
+ }
+ }
+
+ ///
+ /// Stop listening for location updates when the app is in the foreground.
+ /// Has no effect when not listening and
+ /// is currently .
+ ///
+ public void StopListeningForeground()
+ {
+ if (!IsListeningForeground)
+ return;
+
+ listeningManager.StopUpdatingLocation();
+
+ if (listeningManager.Delegate is ContinuousLocationListener listener)
+ {
+ listener.LocationHandler = null;
+ listener.ErrorHandler = null;
+ }
+
+ listeningManager.Delegate = null;
+
+ listeningManager = null;
+ }
}
class SingleLocationListener : CLLocationManagerDelegate
@@ -99,6 +195,7 @@ class SingleLocationListener : CLLocationManagerDelegate
internal Action LocationHandler { get; set; }
+ ///
public override void LocationsUpdated(CLLocationManager manager, CLLocation[] locations)
{
if (wasRaised)
@@ -114,6 +211,43 @@ public override void LocationsUpdated(CLLocationManager manager, CLLocation[] lo
LocationHandler?.Invoke(location);
}
+ ///
+ public override bool ShouldDisplayHeadingCalibration(CLLocationManager manager) => false;
+ }
+
+ class ContinuousLocationListener : CLLocationManagerDelegate
+ {
+ internal Action LocationHandler { get; set; }
+
+ internal Action ErrorHandler { get; set; }
+
+ ///
+ public override void LocationsUpdated(CLLocationManager manager, CLLocation[] locations)
+ {
+ var location = locations?.LastOrDefault();
+
+ if (location == null)
+ return;
+
+ LocationHandler?.Invoke(location);
+ }
+
+ ///
+ public override void Failed(CLLocationManager manager, NSError error)
+ {
+ if ((CLError)error.Code == CLError.Network)
+ ErrorHandler?.Invoke(GeolocationError.PositionUnavailable);
+ }
+
+ ///
+ public override void AuthorizationChanged(CLLocationManager manager, CLAuthorizationStatus status)
+ {
+ if (status == CLAuthorizationStatus.Denied ||
+ status == CLAuthorizationStatus.Restricted)
+ ErrorHandler?.Invoke(GeolocationError.Unauthorized);
+ }
+
+ ///
public override bool ShouldDisplayHeadingCalibration(CLLocationManager manager) => false;
}
}
diff --git a/src/Essentials/src/Geolocation/Geolocation.netstandard.tvos.watchos.cs b/src/Essentials/src/Geolocation/Geolocation.netstandard.tvos.watchos.cs
index 67c10b2ec813..4fc89b6e5a1e 100644
--- a/src/Essentials/src/Geolocation/Geolocation.netstandard.tvos.watchos.cs
+++ b/src/Essentials/src/Geolocation/Geolocation.netstandard.tvos.watchos.cs
@@ -1,3 +1,4 @@
+using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Maui.ApplicationModel;
@@ -11,5 +12,13 @@ public Task GetLastKnownLocationAsync() =>
public Task GetLocationAsync(GeolocationRequest request, CancellationToken cancellationToken) =>
throw ExceptionUtils.NotSupportedOrImplementedException;
+
+ public bool IsListeningForeground { get => false; }
+
+ public Task StartListeningForegroundAsync(GeolocationListeningRequest request) =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
+
+ public void StopListeningForeground() =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
}
}
diff --git a/src/Essentials/src/Geolocation/Geolocation.shared.cs b/src/Essentials/src/Geolocation/Geolocation.shared.cs
index 753d13ed5fc0..64809d25cd89 100644
--- a/src/Essentials/src/Geolocation/Geolocation.shared.cs
+++ b/src/Essentials/src/Geolocation/Geolocation.shared.cs
@@ -1,6 +1,8 @@
#nullable enable
+using System;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
{
@@ -27,6 +29,41 @@ public interface IGeolocation
/// The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.
/// A object containing current location information or if no location could be determined.
Task GetLocationAsync(GeolocationRequest request, CancellationToken cancelToken);
+
+ ///
+ /// Indicates if currently listening to location updates while the app is in foreground.
+ ///
+ bool IsListeningForeground { get; }
+
+ ///
+ /// Occurs while listening to location updates.
+ ///
+ event EventHandler? LocationChanged;
+
+ ///
+ /// Occurs when an error during listening for location updates arises. When the event is
+ /// fired, listening for further location updates has been stopped and no further
+ /// events are sent.
+ ///
+ event EventHandler? ListeningFailed;
+
+ ///
+ /// Starts listening to location updates using the event. Events
+ /// may only sent when the app is in the foreground. Requests
+ /// from the user.
+ ///
+ /// Thrown when is .
+ /// Thrown if listening is not supported on this platform.
+ /// Thrown if already listening and returns .
+ /// The listening request parameters to use.
+ /// when listening was started, or when listening couldn't be started.
+ Task StartListeningForegroundAsync(GeolocationListeningRequest request);
+
+ ///
+ /// Stop listening for location updates when the app is in the foreground.
+ /// Has no effect when is currently .
+ ///
+ void StopListeningForeground();
}
///
@@ -72,6 +109,53 @@ public static partial class Geolocation
public static Task GetLocationAsync(GeolocationRequest request, CancellationToken cancelToken) =>
Current.GetLocationAsync(request, cancelToken);
+ ///
+ /// Indicates if currently listening to location updates while the app is in foreground.
+ ///
+ public static bool IsListeningForeground { get => Current.IsListeningForeground; }
+
+ ///
+ /// Occurs while listening to location updates.
+ ///
+ public static event EventHandler LocationChanged
+ {
+ add => Current.LocationChanged += value;
+ remove => Current.LocationChanged -= value;
+ }
+
+ ///
+ /// Occurs when an error during listening for location updates arises. When the event is
+ /// fired, listening for further location updates has been stopped and no further
+ /// events are sent.
+ ///
+ public static event EventHandler ListeningFailed
+ {
+ add => Current.ListeningFailed += value;
+ remove => Current.ListeningFailed -= value;
+ }
+
+ ///
+ /// Starts listening to location updates using the
+ /// event or the event. Events may only sent when
+ /// the app is in the foreground. Requests
+ /// from the user.
+ ///
+ /// Thrown when is .
+ /// Thrown if listening is not supported on this platform.
+ /// Thrown if already listening and returns .
+ /// The listening request parameters to use.
+ /// when listening was started, or when listening couldn't be started.
+ public static Task StartListeningForegroundAsync(GeolocationListeningRequest request) =>
+ Current.StartListeningForegroundAsync(request);
+
+ ///
+ /// Stop listening for location updates when the app is in the foreground.
+ /// Has no effect when not listening and
+ /// is currently .
+ ///
+ public static void StopListeningForeground() =>
+ Current.StopListeningForeground();
+
static IGeolocation Current => Devices.Sensors.Geolocation.Default;
static IGeolocation? defaultImplementation;
@@ -86,6 +170,22 @@ internal static void SetDefault(IGeolocation? implementation) =>
defaultImplementation = implementation;
}
+ partial class GeolocationImplementation : IGeolocation
+ {
+ public event EventHandler? LocationChanged;
+
+ public event EventHandler? ListeningFailed;
+
+ internal void OnLocationChanged(Location location) =>
+ OnLocationChanged(new GeolocationLocationChangedEventArgs(location));
+
+ internal void OnLocationChanged(GeolocationLocationChangedEventArgs e) =>
+ LocationChanged?.Invoke(null, e);
+
+ internal void OnLocationError(GeolocationError geolocationError) =>
+ ListeningFailed?.Invoke(null, new GeolocationListeningFailedEventArgs(geolocationError));
+ }
+
///
/// Static class with extension methods for the APIs.
///
diff --git a/src/Essentials/src/Geolocation/Geolocation.tizen.cs b/src/Essentials/src/Geolocation/Geolocation.tizen.cs
index 70f601cedbcb..9ed480844860 100644
--- a/src/Essentials/src/Geolocation/Geolocation.tizen.cs
+++ b/src/Essentials/src/Geolocation/Geolocation.tizen.cs
@@ -10,11 +10,13 @@ partial class GeolocationImplementation : IGeolocation
{
Location lastKnownLocation = new Location();
+ public bool IsListeningForeground { get => false; }
+
public Task GetLastKnownLocationAsync() => Task.FromResult(lastKnownLocation);
public async Task GetLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
{
- _ = request ?? throw new ArgumentNullException(nameof(request));
+ ArgumentNullException.ThrowIfNull(request);
await Permissions.EnsureGrantedAsync();
@@ -67,5 +69,11 @@ public async Task GetLocationAsync(GeolocationRequest request, Cancell
return lastKnownLocation;
}
+
+ public Task StartListeningForegroundAsync(GeolocationListeningRequest request) =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
+
+ public void StopListeningForeground() =>
+ throw ExceptionUtils.NotSupportedOrImplementedException;
}
}
diff --git a/src/Essentials/src/Geolocation/Geolocation.uwp.cs b/src/Essentials/src/Geolocation/Geolocation.uwp.cs
index ce9778380055..4c80fbd0b200 100644
--- a/src/Essentials/src/Geolocation/Geolocation.uwp.cs
+++ b/src/Essentials/src/Geolocation/Geolocation.uwp.cs
@@ -9,6 +9,13 @@ namespace Microsoft.Maui.Devices.Sensors
{
partial class GeolocationImplementation : IGeolocation
{
+ Geolocator? listeningGeolocator;
+
+ ///
+ /// Indicates if currently listening to location updates while the app is in foreground.
+ ///
+ public bool IsListeningForeground { get => listeningGeolocator != null; }
+
public async Task GetLastKnownLocationAsync()
{
// no need for permissions as AllowFallbackToConsentlessPositions
@@ -27,7 +34,7 @@ partial class GeolocationImplementation : IGeolocation
public async Task GetLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
{
- _ = request ?? throw new ArgumentNullException(nameof(request));
+ ArgumentNullException.ThrowIfNull(request);
await Permissions.EnsureGrantedAsync();
@@ -43,16 +50,98 @@ partial class GeolocationImplementation : IGeolocation
var location = await geolocator.GetGeopositionAsync().AsTask(cancellationToken);
return location?.Coordinate?.ToLocation();
+ }
- static void CheckStatus(PositionStatus status)
+ static void CheckStatus(PositionStatus status)
+ {
+ switch (status)
{
- switch (status)
- {
- case PositionStatus.Disabled:
- case PositionStatus.NotAvailable:
- throw new FeatureNotEnabledException("Location services are not enabled on device.");
- }
+ case PositionStatus.Disabled:
+ case PositionStatus.NotAvailable:
+ throw new FeatureNotEnabledException("Location services are not enabled on device.");
}
}
+
+ ///
+ /// Starts listening to location updates using the
+ /// event or the event. Events may only sent when
+ /// the app is in the foreground. Requests
+ /// from the user.
+ ///
+ /// Thrown when is .
+ /// Thrown if listening is not supported on this platform.
+ /// Thrown if already listening and returns .
+ /// The listening request parameters to use.
+ /// when listening was started, or when listening couldn't be started.
+ public async Task StartListeningForegroundAsync(GeolocationListeningRequest request)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+
+ if (request.MinimumTime.TotalMilliseconds < 0)
+ throw new ArgumentOutOfRangeException(nameof(request), "MinimumTime must be positive.");
+
+ if (IsListeningForeground)
+ throw new InvalidOperationException("Already listening to location updates.");
+
+ await Permissions.EnsureGrantedAsync();
+
+ listeningGeolocator = new Geolocator
+ {
+ DesiredAccuracyInMeters = request.PlatformDesiredAccuracy,
+ ReportInterval = (uint)request.MinimumTime.TotalMilliseconds,
+ MovementThreshold = request.PlatformDesiredAccuracy,
+ };
+
+ CheckStatus(listeningGeolocator.LocationStatus);
+
+ listeningGeolocator.PositionChanged += OnLocatorPositionChanged;
+ listeningGeolocator.StatusChanged += OnLocatorStatusChanged;
+
+ return true;
+ }
+
+ ///
+ /// Stop listening for location updates when the app is in the foreground.
+ /// Has no effect when not listening and
+ /// is currently .
+ ///
+ public void StopListeningForeground()
+ {
+ if (!IsListeningForeground || listeningGeolocator == null)
+ return;
+
+ listeningGeolocator.PositionChanged -= OnLocatorPositionChanged;
+ listeningGeolocator.StatusChanged -= OnLocatorStatusChanged;
+
+ listeningGeolocator = null;
+ }
+
+ void OnLocatorPositionChanged(Geolocator sender, PositionChangedEventArgs e) =>
+ OnLocationChanged(e.Position.ToLocation());
+
+ void OnLocatorStatusChanged(Geolocator sender, StatusChangedEventArgs e)
+ {
+ if (!IsListeningForeground)
+ return;
+
+ StopListeningForeground();
+
+ GeolocationError error;
+ switch (e.Status)
+ {
+ case PositionStatus.Disabled:
+ error = GeolocationError.Unauthorized;
+ break;
+
+ case PositionStatus.NoData:
+ error = GeolocationError.PositionUnavailable;
+ break;
+
+ default:
+ return;
+ }
+
+ OnLocationError(error);
+ }
}
}
diff --git a/src/Essentials/src/Geolocation/GeolocationAccuracyExtensionMethods.ios.macos.cs b/src/Essentials/src/Geolocation/GeolocationAccuracyExtensionMethods.ios.macos.cs
new file mode 100644
index 000000000000..be42c328cf9a
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationAccuracyExtensionMethods.ios.macos.cs
@@ -0,0 +1,28 @@
+#nullable enable
+using CoreLocation;
+
+namespace Microsoft.Maui.Devices.Sensors
+{
+ static class GeolocationAccuracyExtensionMethods
+ {
+ internal static double PlatformDesiredAccuracy(this GeolocationAccuracy desiredAccuracy)
+ {
+ switch (desiredAccuracy)
+ {
+ case GeolocationAccuracy.Lowest:
+ return CLLocation.AccuracyThreeKilometers;
+ case GeolocationAccuracy.Low:
+ return CLLocation.AccuracyKilometer;
+ case GeolocationAccuracy.Default:
+ case GeolocationAccuracy.Medium:
+ return CLLocation.AccuracyHundredMeters;
+ case GeolocationAccuracy.High:
+ return CLLocation.AccuracyNearestTenMeters;
+ case GeolocationAccuracy.Best:
+ return CLLocation.AccurracyBestForNavigation;
+ default:
+ return CLLocation.AccuracyHundredMeters;
+ }
+ }
+ }
+}
diff --git a/src/Essentials/src/Geolocation/GeolocationAccuracyExtensionMethods.uwp.cs b/src/Essentials/src/Geolocation/GeolocationAccuracyExtensionMethods.uwp.cs
new file mode 100644
index 000000000000..aa5bad7d6e05
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationAccuracyExtensionMethods.uwp.cs
@@ -0,0 +1,25 @@
+namespace Microsoft.Maui.Devices.Sensors
+{
+ static class GeolocationAccuracyExtensionMethods
+ {
+ internal static uint PlatformGetDesiredAccuracy(this GeolocationAccuracy desiredAccuracy)
+ {
+ switch (desiredAccuracy)
+ {
+ case GeolocationAccuracy.Lowest:
+ return 3000;
+ case GeolocationAccuracy.Low:
+ return 1000;
+ case GeolocationAccuracy.Default:
+ case GeolocationAccuracy.Medium:
+ return 100;
+ case GeolocationAccuracy.High:
+ return 10; // Equivalent to PositionAccuracy.High
+ case GeolocationAccuracy.Best:
+ return 1;
+ default:
+ return 500; // Equivalent to PositionAccuracy.Default
+ }
+ }
+ }
+}
diff --git a/src/Essentials/src/Geolocation/GeolocationError.shared.cs b/src/Essentials/src/Geolocation/GeolocationError.shared.cs
new file mode 100644
index 000000000000..5008f4660953
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationError.shared.cs
@@ -0,0 +1,30 @@
+#nullable enable
+
+namespace Microsoft.Maui.Devices.Sensors
+{
+ ///
+ /// Error values for listening for geolocation changes
+ ///
+ public enum GeolocationError
+ {
+ ///
+ /// The provider was unable to retrieve any position data.
+ ///
+ ///
+ /// Android: Sent when no location provider is available that satisfies the requested geolocation accuracy.
+ /// iOS: Getting location data has failed.
+ /// Windows: No location data is available from any source.
+ ///
+ PositionUnavailable,
+
+ ///
+ /// The app is not, or no longer, authorized to receive location data.
+ ///
+ ///
+ /// Android: Not used.
+ /// iOS: Authorization for getting locations has changed.
+ /// Windows: Location sources are turned off.
+ ///
+ Unauthorized,
+ }
+}
\ No newline at end of file
diff --git a/src/Essentials/src/Geolocation/GeolocationListeningFailedEventArgs.shared.cs b/src/Essentials/src/Geolocation/GeolocationListeningFailedEventArgs.shared.cs
new file mode 100644
index 000000000000..f32ca843d6c3
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationListeningFailedEventArgs.shared.cs
@@ -0,0 +1,25 @@
+#nullable enable
+using System;
+
+namespace Microsoft.Maui.Devices.Sensors
+{
+ ///
+ /// Event args for the geolocation listening error event.
+ ///
+ public class GeolocationListeningFailedEventArgs : EventArgs
+ {
+ ///
+ /// The geolocation error that describes the error that occurred.
+ ///
+ public GeolocationError Error { get; }
+
+ ///
+ /// Creates a new geolocation error event args object
+ ///
+ /// gelocation error to use for this object
+ public GeolocationListeningFailedEventArgs(GeolocationError geolocationError)
+ {
+ Error = geolocationError;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Essentials/src/Geolocation/GeolocationListeningRequest.ios.macos.cs b/src/Essentials/src/Geolocation/GeolocationListeningRequest.ios.macos.cs
new file mode 100644
index 000000000000..2bfa09596819
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationListeningRequest.ios.macos.cs
@@ -0,0 +1,15 @@
+#nullable enable
+
+namespace Microsoft.Maui.Devices.Sensors
+{
+ public partial class GeolocationListeningRequest
+ {
+ internal double PlatformDesiredAccuracy
+ {
+ get
+ {
+ return DesiredAccuracy.PlatformDesiredAccuracy();
+ }
+ }
+ }
+}
diff --git a/src/Essentials/src/Geolocation/GeolocationListeningRequest.shared.cs b/src/Essentials/src/Geolocation/GeolocationListeningRequest.shared.cs
new file mode 100644
index 000000000000..7420ca575551
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationListeningRequest.shared.cs
@@ -0,0 +1,51 @@
+#nullable enable
+using System;
+
+namespace Microsoft.Maui.Devices.Sensors
+{
+ ///
+ /// Request options for listening to geolocations
+ ///
+ public partial class GeolocationListeningRequest
+ {
+ ///
+ /// Creates a new request object with default values
+ ///
+ public GeolocationListeningRequest()
+ : this(GeolocationAccuracy.Default)
+ {
+ }
+
+ ///
+ /// Creates a new request object with given accuracy.
+ ///
+ /// The desired geolocation accuracy.
+ public GeolocationListeningRequest(GeolocationAccuracy accuracy)
+ : this(accuracy, TimeSpan.FromSeconds(1))
+ {
+ }
+
+ ///
+ /// Creates a new request object with given accuracy and minimum time.
+ ///
+ /// The desired geolocation accuracy.
+ /// The minimum time between location updates being sent.
+ public GeolocationListeningRequest(GeolocationAccuracy accuracy, TimeSpan minimumTime)
+ {
+ DesiredAccuracy = accuracy;
+ MinimumTime = minimumTime;
+ }
+
+ ///
+ /// Minimum time between location updates being sent. This value must positive. Most location
+ /// sensors may not return locations in intervals shorter than 1 second.
+ ///
+ public TimeSpan MinimumTime { get; set; } = TimeSpan.FromSeconds(1);
+
+ ///
+ /// The desired minimum accuracy for the location updates being sent. Locations that don't
+ /// satisfy this accuracy are not sent using the event handler.
+ ///
+ public GeolocationAccuracy DesiredAccuracy { get; set; } = GeolocationAccuracy.Default;
+ }
+}
diff --git a/src/Essentials/src/Geolocation/GeolocationListeningRequest.uwp.cs b/src/Essentials/src/Geolocation/GeolocationListeningRequest.uwp.cs
new file mode 100644
index 000000000000..d6b276d792e1
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationListeningRequest.uwp.cs
@@ -0,0 +1,15 @@
+#nullable enable
+
+namespace Microsoft.Maui.Devices.Sensors
+{
+ public partial class GeolocationListeningRequest
+ {
+ internal uint PlatformDesiredAccuracy
+ {
+ get
+ {
+ return DesiredAccuracy.PlatformGetDesiredAccuracy();
+ }
+ }
+ }
+}
diff --git a/src/Essentials/src/Geolocation/GeolocationLocationChangedEventArgs.shared.cs b/src/Essentials/src/Geolocation/GeolocationLocationChangedEventArgs.shared.cs
new file mode 100644
index 000000000000..673732b4c807
--- /dev/null
+++ b/src/Essentials/src/Geolocation/GeolocationLocationChangedEventArgs.shared.cs
@@ -0,0 +1,29 @@
+#nullable enable
+using System;
+
+namespace Microsoft.Maui.Devices.Sensors
+{
+ ///
+ /// Event arguments containing the current reading of .
+ ///
+ public class GeolocationLocationChangedEventArgs : EventArgs
+ {
+ ///
+ /// The current reading's location data.
+ ///
+ public Location Location { get; }
+
+ ///
+ /// Public constructor that takes in a reading for event arguments.
+ ///
+ /// The location data reading.
+ /// Thrown when is .
+ public GeolocationLocationChangedEventArgs(Location location)
+ {
+ if (location == null)
+ throw new ArgumentNullException(nameof(location));
+
+ Location = location;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Essentials/src/Geolocation/GeolocationRequest.ios.macos.cs b/src/Essentials/src/Geolocation/GeolocationRequest.ios.macos.cs
index a6a96532e782..616cffec59a9 100644
--- a/src/Essentials/src/Geolocation/GeolocationRequest.ios.macos.cs
+++ b/src/Essentials/src/Geolocation/GeolocationRequest.ios.macos.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using CoreLocation;
+#nullable enable
namespace Microsoft.Maui.Devices.Sensors
{
@@ -11,22 +8,7 @@ internal double PlatformDesiredAccuracy
{
get
{
- switch (DesiredAccuracy)
- {
- case GeolocationAccuracy.Lowest:
- return CLLocation.AccuracyThreeKilometers;
- case GeolocationAccuracy.Low:
- return CLLocation.AccuracyKilometer;
- case GeolocationAccuracy.Default:
- case GeolocationAccuracy.Medium:
- return CLLocation.AccuracyHundredMeters;
- case GeolocationAccuracy.High:
- return CLLocation.AccuracyNearestTenMeters;
- case GeolocationAccuracy.Best:
- return CLLocation.AccurracyBestForNavigation;
- default:
- return CLLocation.AccuracyHundredMeters;
- }
+ return DesiredAccuracy.PlatformDesiredAccuracy();
}
}
}
diff --git a/src/Essentials/src/Geolocation/GeolocationRequest.uwp.cs b/src/Essentials/src/Geolocation/GeolocationRequest.uwp.cs
index f4670c35d0b2..c35c2605fad3 100644
--- a/src/Essentials/src/Geolocation/GeolocationRequest.uwp.cs
+++ b/src/Essentials/src/Geolocation/GeolocationRequest.uwp.cs
@@ -1,7 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
namespace Microsoft.Maui.Devices.Sensors
{
public partial class GeolocationRequest
@@ -10,22 +6,7 @@ internal uint PlatformDesiredAccuracy
{
get
{
- switch (DesiredAccuracy)
- {
- case GeolocationAccuracy.Lowest:
- return 3000;
- case GeolocationAccuracy.Low:
- return 1000;
- case GeolocationAccuracy.Default:
- case GeolocationAccuracy.Medium:
- return 100;
- case GeolocationAccuracy.High:
- return 10; // Equivalent to PositionAccuracy.High
- case GeolocationAccuracy.Best:
- return 1;
- default:
- return 500; // Equivalent to PositionAccuracy.Default
- }
+ return DesiredAccuracy.PlatformGetDesiredAccuracy();
}
}
}
diff --git a/src/Essentials/src/Magnetometer/Magnetometer.shared.cs b/src/Essentials/src/Magnetometer/Magnetometer.shared.cs
index 62066acc08dc..5c0d65d3107c 100644
--- a/src/Essentials/src/Magnetometer/Magnetometer.shared.cs
+++ b/src/Essentials/src/Magnetometer/Magnetometer.shared.cs
@@ -176,6 +176,7 @@ public bool Equals(MagnetometerData other) =>
public static bool operator !=(MagnetometerData left, MagnetometerData right) =>
!left.Equals(right);
+ ///
public override int GetHashCode() =>
MagneticField.GetHashCode();
diff --git a/src/Essentials/src/Map/Map.tizen.cs b/src/Essentials/src/Map/Map.tizen.cs
index 707665064b5c..50807dfe6544 100644
--- a/src/Essentials/src/Map/Map.tizen.cs
+++ b/src/Essentials/src/Map/Map.tizen.cs
@@ -2,8 +2,8 @@
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
-using Tizen.Applications;
using Microsoft.Maui.Devices.Sensors;
+using Tizen.Applications;
namespace Microsoft.Maui.ApplicationModel
{
diff --git a/src/Essentials/src/Map/NavigationMode.shared.cs b/src/Essentials/src/Map/NavigationMode.shared.cs
index 85f66a937637..1a6665cc1598 100644
--- a/src/Essentials/src/Map/NavigationMode.shared.cs
+++ b/src/Essentials/src/Map/NavigationMode.shared.cs
@@ -1,19 +1,26 @@
namespace Microsoft.Maui.ApplicationModel
{
- ///
+ ///
+ /// Represents various modes of navigation that can be passed to the operating system's Maps app.
+ ///
public enum NavigationMode
{
- ///
+ /// No navigation mode.
None = 0,
- ///
+
+ /// The default navigation mode on the platform.
Default = 1,
- ///
+
+ /// Bicycle route mode.
Bicycling = 2,
- ///
+
+ /// Car route mode.
Driving = 3,
- ///
+
+ /// Transit route mode.
Transit = 4,
- ///
+
+ /// Walking route mode.
Walking = 5,
}
}
diff --git a/src/Essentials/src/OrientationSensor/OrientationSensor.shared.cs b/src/Essentials/src/OrientationSensor/OrientationSensor.shared.cs
index d169f8887073..c0d16fea5dab 100644
--- a/src/Essentials/src/OrientationSensor/OrientationSensor.shared.cs
+++ b/src/Essentials/src/OrientationSensor/OrientationSensor.shared.cs
@@ -192,19 +192,39 @@ public override string ToString() =>
$"{nameof(Orientation.W)}: {Orientation.W}";
}
+ ///
+ /// Concrete implementation of the APIs.
+ ///
public partial class OrientationSensorImplementation : IOrientationSensor
{
bool UseSyncContext => SensorSpeed == SensorSpeed.Default || SensorSpeed == SensorSpeed.UI;
SensorSpeed SensorSpeed { get; set; } = SensorSpeed.Default;
+ ///
+ /// Occurs when the orientation reading changes.
+ ///
public event EventHandler? ReadingChanged;
+ ///
+ /// Gets a value indicating whether reading the orientation sensor is supported on this device.
+ ///
public bool IsSupported
=> PlatformIsSupported;
+ ///
+ /// Gets a value indicating whether the orientation sensor is actively being monitored.
+ ///
public bool IsMonitoring { get; private set; }
+ ///
+ /// Start monitoring for changes to the orientation.
+ ///
+ ///
+ /// Will throw if not supported on device.
+ /// Will throw if is .
+ ///
+ /// The speed to listen for changes.
public void Start(SensorSpeed sensorSpeed)
{
if (!PlatformIsSupported)
@@ -227,6 +247,9 @@ public void Start(SensorSpeed sensorSpeed)
}
}
+ ///
+ /// Stop monitoring for changes to the orientation.
+ ///
public void Stop()
{
if (!PlatformIsSupported)
diff --git a/src/Essentials/src/Permissions/Permissions.android.cs b/src/Essentials/src/Permissions/Permissions.android.cs
index 3597a33b4492..4d745cdf5eec 100644
--- a/src/Essentials/src/Permissions/Permissions.android.cs
+++ b/src/Essentials/src/Permissions/Permissions.android.cs
@@ -195,6 +195,37 @@ public override Task CheckStatusAsync() =>
Task.FromResult(IsDeclaredInManifest(Manifest.Permission.BatteryStats) ? PermissionStatus.Granted : PermissionStatus.Denied);
}
+ public partial class Bluetooth : BasePlatformPermission
+ {
+ public override (string androidPermission, bool isRuntime)[] RequiredPermissions
+ {
+ get
+ {
+ var permissions = new List<(string, bool)>();
+
+ // When targeting Android 11 or lower, AccessFineLocation is required for Bluetooth.
+ // For Android 12 and above, it is optional.
+ if (Application.Context.ApplicationInfo.TargetSdkVersion <= BuildVersionCodes.R || IsDeclaredInManifest(Manifest.Permission.AccessFineLocation))
+ permissions.Add((Manifest.Permission.AccessFineLocation, true));
+
+#if __ANDROID_31__
+ if (OperatingSystem.IsAndroidVersionAtLeast(31) && Application.Context.ApplicationInfo.TargetSdkVersion >= BuildVersionCodes.S)
+ {
+ // new runtime permissions on Android 12
+ if (IsDeclaredInManifest(Manifest.Permission.BluetoothScan))
+ permissions.Add((Manifest.Permission.BluetoothScan, true));
+ if (IsDeclaredInManifest(Manifest.Permission.BluetoothConnect))
+ permissions.Add((Manifest.Permission.BluetoothConnect, true));
+ if (IsDeclaredInManifest(Manifest.Permission.BluetoothAdvertise))
+ permissions.Add((Manifest.Permission.BluetoothAdvertise, true));
+ }
+#endif
+
+ return permissions.ToArray();
+ }
+ }
+ }
+
public partial class CalendarRead : BasePlatformPermission
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
diff --git a/src/Essentials/src/Permissions/Permissions.ios.tvos.watchos.cs b/src/Essentials/src/Permissions/Permissions.ios.tvos.watchos.cs
index 47f510377554..3a3733ba7854 100644
--- a/src/Essentials/src/Permissions/Permissions.ios.tvos.watchos.cs
+++ b/src/Essentials/src/Permissions/Permissions.ios.tvos.watchos.cs
@@ -80,6 +80,10 @@ public partial class Battery : BasePlatformPermission
{
}
+ public partial class Bluetooth : BasePlatformPermission
+ {
+ }
+
public partial class CalendarRead : BasePlatformPermission
{
}
diff --git a/src/Essentials/src/Permissions/Permissions.macos.cs b/src/Essentials/src/Permissions/Permissions.macos.cs
index 50319daaf129..8b7a4d110361 100644
--- a/src/Essentials/src/Permissions/Permissions.macos.cs
+++ b/src/Essentials/src/Permissions/Permissions.macos.cs
@@ -68,6 +68,10 @@ public partial class Battery : BasePlatformPermission
{
}
+ public partial class Bluetooth : BasePlatformPermission
+ {
+ }
+
public partial class CalendarRead : BasePlatformPermission
{
}
diff --git a/src/Essentials/src/Permissions/Permissions.netstandard.cs b/src/Essentials/src/Permissions/Permissions.netstandard.cs
index f9efd605e967..78da5bf1d41f 100644
--- a/src/Essentials/src/Permissions/Permissions.netstandard.cs
+++ b/src/Essentials/src/Permissions/Permissions.netstandard.cs
@@ -37,6 +37,10 @@ public partial class Battery : BasePlatformPermission
{
}
+ public partial class Bluetooth : BasePlatformPermission
+ {
+ }
+
public partial class CalendarRead : BasePlatformPermission
{
}
diff --git a/src/Essentials/src/Permissions/Permissions.shared.cs b/src/Essentials/src/Permissions/Permissions.shared.cs
index 022e4b4e5b83..df4b3852391b 100644
--- a/src/Essentials/src/Permissions/Permissions.shared.cs
+++ b/src/Essentials/src/Permissions/Permissions.shared.cs
@@ -126,6 +126,13 @@ public partial class Battery
{
}
+ ///
+ /// Represents permission to communicate via Bluetooth (scanning, connecting and/or advertising).
+ ///
+ public partial class Bluetooth
+ {
+ }
+
///
/// Represents permission to read the device calendar information.
///
diff --git a/src/Essentials/src/Permissions/Permissions.tizen.cs b/src/Essentials/src/Permissions/Permissions.tizen.cs
index 9fb9308667ee..9d33b770da8f 100644
--- a/src/Essentials/src/Permissions/Permissions.tizen.cs
+++ b/src/Essentials/src/Permissions/Permissions.tizen.cs
@@ -6,6 +6,11 @@ namespace Microsoft.Maui.ApplicationModel
{
public static partial class Permissions
{
+ ///
+ /// Checks if the key specified in is declared in the application's tizen-manifest.xml file.
+ ///
+ /// The key to check for declaration in the tizen-manifest.xml file.
+ /// when the key is declared, otherwise .
public static bool IsPrivilegeDeclared(string tizenPrivilege)
{
var tizenPrivileges = tizenPrivilege;
@@ -21,13 +26,19 @@ public static bool IsPrivilegeDeclared(string tizenPrivilege)
return true;
}
+ ///
public abstract partial class BasePlatformPermission : BasePermission
{
+ ///
+ /// Gets the required entries that need to be present in the application's tizen-manifest.xml file for this permission.
+ ///
public virtual (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges { get; }
+ ///
public override Task CheckStatusAsync()
=> CheckPrivilegeAsync(false);
+ ///
public override Task RequestAsync()
=> CheckPrivilegeAsync(true);
@@ -71,6 +82,7 @@ void OnResponseFetched(object sender, RequestResponseEventArgs e)
return PermissionStatus.Granted;
}
+ ///
public override void EnsureDeclared()
{
if (RequiredPrivileges == null)
@@ -83,6 +95,7 @@ public override void EnsureDeclared()
}
}
+ ///
public override bool ShouldShowRationale() => false;
}
@@ -90,6 +103,10 @@ public partial class Battery : BasePlatformPermission
{
}
+ public partial class Bluetooth : BasePlatformPermission
+ {
+ }
+
public partial class CalendarRead : BasePlatformPermission
{
}
@@ -100,48 +117,56 @@ public partial class CalendarWrite : BasePlatformPermission
public partial class Camera : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/camera", false) };
}
public partial class ContactsRead : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/contact.read", true) };
}
public partial class ContactsWrite : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/contact.write", true) };
}
public partial class Flashlight : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/led", false) };
}
public partial class LaunchApp : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/appmanager.launch", false) };
}
public partial class LocationWhenInUse : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/location", true) };
}
public partial class LocationAlways : LocationWhenInUse
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/location", true) };
}
public partial class Maps : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[]
{
@@ -157,12 +182,14 @@ public partial class Media : BasePlatformPermission
public partial class Microphone : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/recorder", false) };
}
public partial class NetworkState : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[]
{
@@ -197,18 +224,21 @@ public partial class Speech : BasePlatformPermission
public partial class StorageRead : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/mediastorage", true) };
}
public partial class StorageWrite : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/mediastorage", true) };
}
public partial class Vibrate : BasePlatformPermission
{
+ ///
public override (string tizenPrivilege, bool isRuntime)[] RequiredPrivileges =>
new[] { ("http://tizen.org/privilege/haptic", false) };
}
diff --git a/src/Essentials/src/Permissions/Permissions.uwp.cs b/src/Essentials/src/Permissions/Permissions.uwp.cs
index eec25354d876..a05a59534ad2 100644
--- a/src/Essentials/src/Permissions/Permissions.uwp.cs
+++ b/src/Essentials/src/Permissions/Permissions.uwp.cs
@@ -75,6 +75,10 @@ public partial class Battery : BasePlatformPermission
{
}
+ public partial class Bluetooth : BasePlatformPermission
+ {
+ }
+
public partial class CalendarRead : BasePlatformPermission
{
}
diff --git a/src/Essentials/src/PhoneDialer/PhoneDialer.shared.cs b/src/Essentials/src/PhoneDialer/PhoneDialer.shared.cs
index 6b5cb34a1365..47cf6541640f 100644
--- a/src/Essentials/src/PhoneDialer/PhoneDialer.shared.cs
+++ b/src/Essentials/src/PhoneDialer/PhoneDialer.shared.cs
@@ -35,7 +35,7 @@ public static class PhoneDialer
/// Gets a value indicating whether using the phone dialer is supported on this device.
///
public static bool IsSupported =>
- Current.IsSupported;
+ Default.IsSupported;
///
/// Open the phone dialer to a specific phone number.
@@ -48,9 +48,7 @@ public static class PhoneDialer
/// Thrown if making phone calls is not supported on the device.
/// Phone number to initialize the dialer with.
public static void Open(string number)
- => Current.Open(number);
-
- public static IPhoneDialer Current => ApplicationModel.Communication.PhoneDialer.Default;
+ => Default.Open(number);
static IPhoneDialer? defaultImplementation;
diff --git a/src/Essentials/src/Platform/ActivityStateManager.android.cs b/src/Essentials/src/Platform/ActivityStateManager.android.cs
index 882b38391d0a..f90d127ce57c 100644
--- a/src/Essentials/src/Platform/ActivityStateManager.android.cs
+++ b/src/Essentials/src/Platform/ActivityStateManager.android.cs
@@ -8,23 +8,52 @@
namespace Microsoft.Maui.ApplicationModel
{
+ ///
+ /// Represents a manager object that can handle states.
+ ///
public interface IActivityStateManager
{
+ ///
+ /// Initializes the for the given .
+ ///
+ /// The to use for initialization.
void Init(Application application);
+ ///
+ /// Initializes the for the given and .
+ ///
+ /// The to use for initialization.
+ /// The to use for initialization.
void Init(Activity activity, Bundle? bundle);
+ ///
+ /// Gets the object that represents the application's current activity.
+ ///
Activity? GetCurrentActivity();
+ ///
+ /// Occurs when the state of an activity of this application changes.
+ ///
event EventHandler ActivityStateChanged;
+ ///
+ /// Waits for a to be created or resumed.
+ ///
+ /// A token that can be used for cancelling the operation.
+ /// The application's current or the that has been created or resumed.
Task WaitForActivityAsync(CancellationToken cancelToken = default);
}
+ ///
+ /// Represents a manager object that can handle states.
+ ///
public static class ActivityStateManager
{
static IActivityStateManager? defaultImplementation;
+ ///
+ /// Provides the default implementation for static usage of this API.
+ ///
public static IActivityStateManager Default =>
defaultImplementation ??= new ActivityStateManagerImplementation();
@@ -88,6 +117,12 @@ void OnActivityStateChanged(Activity activity, ActivityState ev)
static class ActivityStateManagerExtensions
{
+ ///
+ /// Gets the object that represents the application's current activity.
+ ///
+ /// The object to invoke this method on.
+ /// Throws an exception if no current can be found and this value is set to , otherwise this method returns .
+ /// Thrown if no current can be found and is set to .
public static Activity? GetCurrentActivity(this IActivityStateManager manager, bool throwOnNull)
{
var activity = manager.GetCurrentActivity();
@@ -98,14 +133,30 @@ static class ActivityStateManagerExtensions
}
}
+ ///
+ /// Represents states that a can have.
+ ///
public enum ActivityState
{
+ /// The activity is created.
Created,
+
+ /// The activity is resumed.
Resumed,
+
+ /// The activity is paused.
Paused,
+
+ /// The activity is destroyed.
Destroyed,
+
+ /// The activity saving the instance state.
SaveInstanceState,
+
+ /// The activity is started.
Started,
+
+ /// The activity is stopped.
Stopped
}
diff --git a/src/Essentials/src/Platform/Platform.shared.cs b/src/Essentials/src/Platform/Platform.shared.cs
index ecdf3a90b549..6ef20cb0544d 100644
--- a/src/Essentials/src/Platform/Platform.shared.cs
+++ b/src/Essentials/src/Platform/Platform.shared.cs
@@ -7,82 +7,148 @@
namespace Microsoft.Maui.ApplicationModel
{
+ ///
+ /// A static class that contains platform-specific helper methods.
+ ///
public static class Platform
{
#if ANDROID
-
+ ///
+ /// A static class that contains Android specific information about .
+ ///
public static class Intent
{
+ ///
+ /// The identifier for the used by .
+ ///
public const string ActionAppAction = AppActionsImplementation.IntentAction;
}
+ ///
+ /// Gets the object that represents the current application context.
+ ///
public static Android.Content.Context AppContext => Android.App.Application.Context;
// ActivityStateManager
+ ///
public static Android.App.Activity? CurrentActivity =>
ActivityStateManager.Default.GetCurrentActivity();
+
+ ///
public static event EventHandler? ActivityStateChanged
{
add => ActivityStateManager.Default.ActivityStateChanged += value;
remove => ActivityStateManager.Default.ActivityStateChanged -= value;
}
+ ///
public static Task WaitForActivityAsync(CancellationToken cancelToken = default) =>
ActivityStateManager.Default.WaitForActivityAsync(cancelToken);
+ ///
public static void Init(Android.App.Application application) =>
ActivityStateManager.Default.Init(application);
+ ///
public static void Init(Android.App.Activity activity, Android.OS.Bundle? bundle) =>
ActivityStateManager.Default.Init(activity, bundle);
// Permissions
+ ///
+ /// Pass permission request results from an activity's overridden method to the library for handling internal permission requests.
+ ///
+ /// The requestCode from the corresponding overridden method in an activity.
+ /// The permissions from the corresponding overridden method in an activity.
+ /// The grantResults from the corresponding overridden method in an activity.
public static void OnRequestPermissionsResult(int requestCode, string[] permissions, Android.Content.PM.Permission[] grantResults) =>
Permissions.OnRequestPermissionsResult(requestCode, permissions, grantResults);
// AppActions
+ ///
+ /// Called when a new was created as part of invoking an app action.
+ ///
+ /// The that is created.
public static void OnNewIntent(Android.Content.Intent? intent) =>
AppActions.Current.OnNewIntent(intent);
+ ///
+ /// Called when a is resumed as part of invoking an app action.
+ ///
+ /// The that is resumed.
public static void OnResume(Android.App.Activity? activity = null) =>
AppActions.Current.OnResume(activity?.Intent);
#elif IOS || MACCATALYST
-
+ ///
+ /// Opens the specified URI to start a authentication flow.
+ ///
+ /// This parameters is not used.
+ /// The URL to open that will start the authentication flow.
+ /// This parameters is not used.
+ /// when the URI has been opened, otherwise .
public static bool OpenUrl(UIKit.UIApplication app, Foundation.NSUrl url, Foundation.NSDictionary options) =>
WebAuthenticator.Default.OpenUrl(app, url, options);
+ ///
+ /// Informs the app that there is data associated with continuing a task specified as a object, and then returns whether the app continued the activity.
+ ///
+ /// The application this action is invoked on.
+ /// The user activity identifier.
+ /// The action that is invoked when the operation is completed.
+ /// if the app handled the user activity, otherwise .
public static bool ContinueUserActivity(UIKit.UIApplication application, Foundation.NSUserActivity userActivity, UIKit.UIApplicationRestorationHandler completionHandler) =>
WebAuthenticator.Default.ContinueUserActivity(application, userActivity, completionHandler);
+ ///
+ /// Invokes the action that corresponds to the chosen by the user.
+ ///
+ /// The application this action is invoked on.
+ /// The shortcut item that was chosen by the user.
+ /// The action that is invoked when the operation is completed.
public static void PerformActionForShortcutItem(UIKit.UIApplication application, UIKit.UIApplicationShortcutItem shortcutItem, UIKit.UIOperationHandler completionHandler) =>
AppActions.Current.PerformActionForShortcutItem(application, shortcutItem, completionHandler);
+ ///
+ /// Initializes the for the given .
+ ///
+ /// The to use for initialization.
public static void Init(Func? getCurrentUIViewController) =>
WindowStateManager.Default.Init(getCurrentUIViewController);
+ ///
+ /// Gets the current view controller through the .
+ ///
+ /// The object that is currently presented.
+ /// Thrown if no current can be found.
public static UIKit.UIViewController? GetCurrentUIViewController() =>
WindowStateManager.Default.GetCurrentUIViewController(true);
#elif WINDOWS
-
+ ///
+ /// Gets or sets the map service API key for this platform.
+ ///
public static string? MapServiceToken
{
get => Geocoding.Default.GetMapServiceToken();
set => Geocoding.Default.SetMapServiceToken(value);
}
+ ///
public static void OnLaunched(UI.Xaml.LaunchActivatedEventArgs e) =>
AppActions.Current.OnLaunched(e);
+ ///
public static void OnActivated(UI.Xaml.Window window, UI.Xaml.WindowActivatedEventArgs args) =>
WindowStateManager.Default.OnActivated(window, args);
#elif TIZEN
+ ///
+ /// Gets a object with information about the current application package.
+ ///
public static Tizen.Applications.Package CurrentPackage
{
get
@@ -92,12 +158,14 @@ public static Tizen.Applications.Package CurrentPackage
}
}
+ ///
+ /// Gets or sets the map service API key for this platform.
+ ///
public static string? MapServiceToken
{
get => Geocoding.Default.GetMapServiceToken();
set => Geocoding.Default.SetMapServiceToken(value);
}
-
#endif
}
diff --git a/src/Essentials/src/Platform/WindowStateManager.ios.cs b/src/Essentials/src/Platform/WindowStateManager.ios.cs
index 16e64f18a1bf..1d7fe3f74ba7 100644
--- a/src/Essentials/src/Platform/WindowStateManager.ios.cs
+++ b/src/Essentials/src/Platform/WindowStateManager.ios.cs
@@ -5,19 +5,40 @@
namespace Microsoft.Maui.ApplicationModel
{
+ ///
+ /// Manager object that manages window states on iOS and macOS.
+ ///
public interface IWindowStateManager
{
+ ///
+ /// Initializes this instance.
+ ///
+ /// The function task to retrieve the current .
void Init(Func? getCurrentUIViewController);
+ ///
+ /// Gets the currently presented .
+ ///
+ /// The object that is currently presented.
UIViewController? GetCurrentUIViewController();
+ ///
+ /// Gets the currently active .
+ ///
+ /// The object that is currently active.
UIWindow? GetCurrentUIWindow();
}
+ ///
+ /// Manager object that manages window states on iOS and macOS.
+ ///
public static class WindowStateManager
{
static IWindowStateManager? defaultImplementation;
+ ///
+ /// Provides the default implementation for static usage of this API.
+ ///
public static IWindowStateManager Default =>
defaultImplementation ??= new WindowStateManagerImplementation();
@@ -27,6 +48,13 @@ internal static void SetDefault(IWindowStateManager? implementation) =>
static class WindowStateManagerExtensions
{
+ ///
+ /// Gets the currently presented .
+ ///
+ /// The object to invoke this method on.
+ /// Throws an exception if no current can be found and this value is set to , otherwise this method returns .
+ /// The object that is currently presented.
+ /// Thrown if no current can be found and is set to .
public static UIViewController? GetCurrentUIViewController(this IWindowStateManager manager, bool throwOnNull)
{
var vc = manager.GetCurrentUIViewController();
@@ -35,6 +63,14 @@ static class WindowStateManagerExtensions
return vc;
}
+
+ ///
+ /// Gets the currently active .
+ ///
+ /// The object to invoke this method on.
+ /// Throws an exception if no current can be found and this value is set to , otherwise this method returns .
+ /// The object that is currently active.
+ /// Thrown if no current can be found and is set to .
public static UIWindow? GetCurrentUIWindow(this IWindowStateManager manager, bool throwOnNull)
{
var window = manager.GetCurrentUIWindow();
diff --git a/src/Essentials/src/Platform/WindowStateManager.uwp.cs b/src/Essentials/src/Platform/WindowStateManager.uwp.cs
index e6848ecab142..ac22d2bcb4f3 100644
--- a/src/Essentials/src/Platform/WindowStateManager.uwp.cs
+++ b/src/Essentials/src/Platform/WindowStateManager.uwp.cs
@@ -5,19 +5,40 @@
namespace Microsoft.Maui.ApplicationModel
{
+ ///
+ /// Manager object that manages window states on Windows.
+ ///
public interface IWindowStateManager
{
+ ///
+ /// Occurs when the application's active window changed.
+ ///
event EventHandler ActiveWindowChanged;
+ ///
+ /// Gets the application's currently active window.
+ ///
+ /// The application's currently active object.
Window? GetActiveWindow();
+ ///
+ /// Sets the new active window that can be retrieved with .
+ ///
+ /// The object that is activated.
+ /// The associated event arguments for this window activation event.
void OnActivated(Window window, WindowActivatedEventArgs args);
}
+ ///
+ /// Manager object that manages window states on Windows.
+ ///
public static class WindowStateManager
{
static IWindowStateManager? defaultImplementation;
+ ///
+ /// Provides the default implementation for static usage of this API.
+ ///
public static IWindowStateManager Default =>
defaultImplementation ??= new WindowStateManagerImplementation();
@@ -27,6 +48,13 @@ internal static void SetDefault(IWindowStateManager? implementation) =>
static class WindowStateManagerExtensions
{
+ ///
+ /// Gets the application's currently active window.
+ ///
+ /// The object to invoke this method on.
+ /// Throws an exception if no current can be found and this value is set to , otherwise this method returns .
+ /// The application's currently active object.
+ /// Thrown if no current can be found and is set to .
public static Window? GetActiveWindow(this IWindowStateManager manager, bool throwOnNull)
{
var window = manager.GetActiveWindow();
@@ -36,6 +64,13 @@ static class WindowStateManagerExtensions
return window;
}
+ ///
+ /// Gets the application's currently active window's pointer.
+ ///
+ /// The object to invoke this method on.
+ /// Throws an exception if no current can be found and this value is set to , otherwise this method returns .
+ /// The application's currently active window's .
+ /// Thrown if no current can be found and is set to .
public static IntPtr GetActiveWindowHandle(this IWindowStateManager manager, bool throwOnNull)
{
var window = manager.GetActiveWindow();
@@ -50,6 +85,13 @@ public static IntPtr GetActiveWindowHandle(this IWindowStateManager manager, boo
return handle;
}
+ ///
+ /// Gets the application's currently active app window.
+ ///
+ /// The object to invoke this method on.
+ /// Throws an exception if no current can be found and this value is set to , otherwise this method returns .
+ /// The application's currently active object.
+ /// Thrown if no current can be found and is set to .
public static AppWindow? GetActiveAppWindow(this IWindowStateManager manager, bool throwOnNull)
{
var window = manager.GetActiveWindow();
diff --git a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt
index 550894fd9814..6f7b5adebfa2 100644
--- a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt
+++ b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Shipped.txt
@@ -78,6 +78,7 @@
~override Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.RequestAsync() -> System.Threading.Tasks.Task
~override Microsoft.Maui.ApplicationModel.Permissions.Battery.CheckStatusAsync() -> System.Threading.Tasks.Task
~override Microsoft.Maui.ApplicationModel.Permissions.Battery.RequiredPermissions.get -> (string androidPermission, bool isRuntime)[]
+~override Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.RequiredPermissions.get -> (string androidPermission, bool isRuntime)[]
~override Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.RequiredPermissions.get -> (string androidPermission, bool isRuntime)[]
~override Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite.RequiredPermissions.get -> (string androidPermission, bool isRuntime)[]
~override Microsoft.Maui.ApplicationModel.Permissions.Camera.RequiredPermissions.get -> (string androidPermission, bool isRuntime)[]
@@ -396,6 +397,8 @@ Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.BasePlatformPermission() -> void
Microsoft.Maui.ApplicationModel.Permissions.Battery
Microsoft.Maui.ApplicationModel.Permissions.Battery.Battery() -> void
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.Bluetooth() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.CalendarRead() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite
diff --git a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
index 1e2c3171b21e..c64aedf4601a 100644
--- a/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -1,5 +1,39 @@
#nullable enable
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void
*REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
*REMOVED*static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.PositionUnavailable = 0 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.Unauthorized = 1 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.Error.get -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.GeolocationListeningFailedEventArgs(Microsoft.Maui.Devices.Sensors.GeolocationError geolocationError) -> void
+Microsoft.Maui.Devices.Sensors.IGeolocation.ListeningFailed -> System.EventHandler?
Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.ListeningFailed -> System.EventHandler!
static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.IsListeningForeground.get -> bool
+Microsoft.Maui.Devices.Sensors.IGeolocation.LocationChanged -> System.EventHandler?
+Microsoft.Maui.Devices.Sensors.IGeolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.StopListeningForeground() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.get -> Microsoft.Maui.Devices.Sensors.GeolocationAccuracy
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy, System.TimeSpan minimumTime) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.get -> System.TimeSpan
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.Location.get -> Microsoft.Maui.Devices.Sensors.Location!
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.GeolocationLocationChangedEventArgs(Microsoft.Maui.Devices.Sensors.Location! location) -> void
+static Microsoft.Maui.Devices.Sensors.Geolocation.IsListeningForeground.get -> bool
+static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.EventHandler!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void
+*REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer!
diff --git a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt
index 50e063865002..7b0a8619e9a4 100644
--- a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt
+++ b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Shipped.txt
@@ -395,6 +395,8 @@ Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.BasePlatformPermission() -> void
Microsoft.Maui.ApplicationModel.Permissions.Battery
Microsoft.Maui.ApplicationModel.Permissions.Battery.Battery() -> void
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.Bluetooth() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.CalendarRead() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite
diff --git a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index 1e2c3171b21e..c64aedf4601a 100644
--- a/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -1,5 +1,39 @@
#nullable enable
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void
*REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
*REMOVED*static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.PositionUnavailable = 0 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.Unauthorized = 1 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.Error.get -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.GeolocationListeningFailedEventArgs(Microsoft.Maui.Devices.Sensors.GeolocationError geolocationError) -> void
+Microsoft.Maui.Devices.Sensors.IGeolocation.ListeningFailed -> System.EventHandler?
Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.ListeningFailed -> System.EventHandler!
static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.IsListeningForeground.get -> bool
+Microsoft.Maui.Devices.Sensors.IGeolocation.LocationChanged -> System.EventHandler?
+Microsoft.Maui.Devices.Sensors.IGeolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.StopListeningForeground() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.get -> Microsoft.Maui.Devices.Sensors.GeolocationAccuracy
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy, System.TimeSpan minimumTime) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.get -> System.TimeSpan
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.Location.get -> Microsoft.Maui.Devices.Sensors.Location!
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.GeolocationLocationChangedEventArgs(Microsoft.Maui.Devices.Sensors.Location! location) -> void
+static Microsoft.Maui.Devices.Sensors.Geolocation.IsListeningForeground.get -> bool
+static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.EventHandler!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void
+*REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer!
diff --git a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt
index 50e063865002..7b0a8619e9a4 100644
--- a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt
+++ b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Shipped.txt
@@ -395,6 +395,8 @@ Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.BasePlatformPermission() -> void
Microsoft.Maui.ApplicationModel.Permissions.Battery
Microsoft.Maui.ApplicationModel.Permissions.Battery.Battery() -> void
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.Bluetooth() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.CalendarRead() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite
diff --git a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index 1e2c3171b21e..c64aedf4601a 100644
--- a/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -1,5 +1,39 @@
#nullable enable
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void
*REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
*REMOVED*static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.PositionUnavailable = 0 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.Unauthorized = 1 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.Error.get -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.GeolocationListeningFailedEventArgs(Microsoft.Maui.Devices.Sensors.GeolocationError geolocationError) -> void
+Microsoft.Maui.Devices.Sensors.IGeolocation.ListeningFailed -> System.EventHandler?
Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.ListeningFailed -> System.EventHandler!
static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.IsListeningForeground.get -> bool
+Microsoft.Maui.Devices.Sensors.IGeolocation.LocationChanged -> System.EventHandler?
+Microsoft.Maui.Devices.Sensors.IGeolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.StopListeningForeground() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.get -> Microsoft.Maui.Devices.Sensors.GeolocationAccuracy
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy, System.TimeSpan minimumTime) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.get -> System.TimeSpan
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.Location.get -> Microsoft.Maui.Devices.Sensors.Location!
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.GeolocationLocationChangedEventArgs(Microsoft.Maui.Devices.Sensors.Location! location) -> void
+static Microsoft.Maui.Devices.Sensors.Geolocation.IsListeningForeground.get -> bool
+static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.EventHandler!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void
+*REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer!
diff --git a/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Shipped.txt
index 76586873abf9..3c34f2b1ed5e 100644
--- a/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Shipped.txt
+++ b/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Shipped.txt
@@ -361,6 +361,8 @@ Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.BasePlatformPermission() -> void
Microsoft.Maui.ApplicationModel.Permissions.Battery
Microsoft.Maui.ApplicationModel.Permissions.Battery.Battery() -> void
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.Bluetooth() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.CalendarRead() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite
diff --git a/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index 1e2c3171b21e..c64aedf4601a 100644
--- a/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -1,5 +1,39 @@
#nullable enable
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void
*REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
*REMOVED*static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.PositionUnavailable = 0 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.Unauthorized = 1 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.Error.get -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.GeolocationListeningFailedEventArgs(Microsoft.Maui.Devices.Sensors.GeolocationError geolocationError) -> void
+Microsoft.Maui.Devices.Sensors.IGeolocation.ListeningFailed -> System.EventHandler?
Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.ListeningFailed -> System.EventHandler!
static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.IsListeningForeground.get -> bool
+Microsoft.Maui.Devices.Sensors.IGeolocation.LocationChanged -> System.EventHandler?
+Microsoft.Maui.Devices.Sensors.IGeolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.StopListeningForeground() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.get -> Microsoft.Maui.Devices.Sensors.GeolocationAccuracy
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy, System.TimeSpan minimumTime) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.get -> System.TimeSpan
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.Location.get -> Microsoft.Maui.Devices.Sensors.Location!
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.GeolocationLocationChangedEventArgs(Microsoft.Maui.Devices.Sensors.Location! location) -> void
+static Microsoft.Maui.Devices.Sensors.Geolocation.IsListeningForeground.get -> bool
+static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.EventHandler!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void
+*REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer!
diff --git a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt
index 095120aa2c08..ade1aa1609b9 100644
--- a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt
+++ b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Shipped.txt
@@ -358,6 +358,8 @@ Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.BasePlatformPermission() -> void
Microsoft.Maui.ApplicationModel.Permissions.Battery
Microsoft.Maui.ApplicationModel.Permissions.Battery.Battery() -> void
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.Bluetooth() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.CalendarRead() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite
diff --git a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index 1e2c3171b21e..c64aedf4601a 100644
--- a/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -1,5 +1,39 @@
#nullable enable
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void
*REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
*REMOVED*static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.PositionUnavailable = 0 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.Unauthorized = 1 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.Error.get -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.GeolocationListeningFailedEventArgs(Microsoft.Maui.Devices.Sensors.GeolocationError geolocationError) -> void
+Microsoft.Maui.Devices.Sensors.IGeolocation.ListeningFailed -> System.EventHandler?
Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.ListeningFailed -> System.EventHandler!
static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.IsListeningForeground.get -> bool
+Microsoft.Maui.Devices.Sensors.IGeolocation.LocationChanged -> System.EventHandler?
+Microsoft.Maui.Devices.Sensors.IGeolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.StopListeningForeground() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.get -> Microsoft.Maui.Devices.Sensors.GeolocationAccuracy
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy, System.TimeSpan minimumTime) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.get -> System.TimeSpan
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.Location.get -> Microsoft.Maui.Devices.Sensors.Location!
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.GeolocationLocationChangedEventArgs(Microsoft.Maui.Devices.Sensors.Location! location) -> void
+static Microsoft.Maui.Devices.Sensors.Geolocation.IsListeningForeground.get -> bool
+static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.EventHandler!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void
+*REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer!
diff --git a/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt
index b92e8889b0e3..5659395d0778 100644
--- a/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt
+++ b/src/Essentials/src/PublicAPI/net/PublicAPI.Shipped.txt
@@ -346,6 +346,8 @@ Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.BasePlatformPermission() -> void
Microsoft.Maui.ApplicationModel.Permissions.Battery
Microsoft.Maui.ApplicationModel.Permissions.Battery.Battery() -> void
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.Bluetooth() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.CalendarRead() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite
diff --git a/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt
index 1e2c3171b21e..c64aedf4601a 100644
--- a/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -1,5 +1,39 @@
#nullable enable
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void
*REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
*REMOVED*static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.PositionUnavailable = 0 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.Unauthorized = 1 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.Error.get -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.GeolocationListeningFailedEventArgs(Microsoft.Maui.Devices.Sensors.GeolocationError geolocationError) -> void
+Microsoft.Maui.Devices.Sensors.IGeolocation.ListeningFailed -> System.EventHandler?
Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.ListeningFailed -> System.EventHandler!
static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.IsListeningForeground.get -> bool
+Microsoft.Maui.Devices.Sensors.IGeolocation.LocationChanged -> System.EventHandler?
+Microsoft.Maui.Devices.Sensors.IGeolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.StopListeningForeground() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.get -> Microsoft.Maui.Devices.Sensors.GeolocationAccuracy
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy, System.TimeSpan minimumTime) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.get -> System.TimeSpan
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.Location.get -> Microsoft.Maui.Devices.Sensors.Location!
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.GeolocationLocationChangedEventArgs(Microsoft.Maui.Devices.Sensors.Location! location) -> void
+static Microsoft.Maui.Devices.Sensors.Geolocation.IsListeningForeground.get -> bool
+static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.EventHandler!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void
+*REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer!
diff --git a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt
index b92e8889b0e3..5659395d0778 100644
--- a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt
+++ b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Shipped.txt
@@ -346,6 +346,8 @@ Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission
Microsoft.Maui.ApplicationModel.Permissions.BasePlatformPermission.BasePlatformPermission() -> void
Microsoft.Maui.ApplicationModel.Permissions.Battery
Microsoft.Maui.ApplicationModel.Permissions.Battery.Battery() -> void
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth
+Microsoft.Maui.ApplicationModel.Permissions.Bluetooth.Bluetooth() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead
Microsoft.Maui.ApplicationModel.Permissions.CalendarRead.CalendarRead() -> void
Microsoft.Maui.ApplicationModel.Permissions.CalendarWrite
diff --git a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index 1e2c3171b21e..c64aedf4601a 100644
--- a/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Essentials/src/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -1,5 +1,39 @@
#nullable enable
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder
+Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder.DecodeResponse(System.Uri! uri) -> System.Collections.Generic.IDictionary?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.get -> Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder?
+Microsoft.Maui.Authentication.WebAuthenticatorOptions.ResponseDecoder.set -> void
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.CallbackUri.get -> System.Uri
+~Microsoft.Maui.Authentication.WebAuthenticatorResult.WebAuthenticatorResult(System.Uri uri, Microsoft.Maui.Authentication.IWebAuthenticatorResponseDecoder responseDecoder) -> void
*REMOVED*Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
*REMOVED*static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.PositionUnavailable = 0 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationError.Unauthorized = 1 -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.Error.get -> Microsoft.Maui.Devices.Sensors.GeolocationError
+Microsoft.Maui.Devices.Sensors.GeolocationListeningFailedEventArgs.GeolocationListeningFailedEventArgs(Microsoft.Maui.Devices.Sensors.GeolocationError geolocationError) -> void
+Microsoft.Maui.Devices.Sensors.IGeolocation.ListeningFailed -> System.EventHandler?
Microsoft.Maui.Storage.ISecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.ListeningFailed -> System.EventHandler!
static Microsoft.Maui.Storage.SecureStorage.GetAsync(string! key) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.IsListeningForeground.get -> bool
+Microsoft.Maui.Devices.Sensors.IGeolocation.LocationChanged -> System.EventHandler?
+Microsoft.Maui.Devices.Sensors.IGeolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+Microsoft.Maui.Devices.Sensors.IGeolocation.StopListeningForeground() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.get -> Microsoft.Maui.Devices.Sensors.GeolocationAccuracy
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.DesiredAccuracy.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest() -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.GeolocationListeningRequest(Microsoft.Maui.Devices.Sensors.GeolocationAccuracy accuracy, System.TimeSpan minimumTime) -> void
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.get -> System.TimeSpan
+Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest.MinimumTime.set -> void
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.Location.get -> Microsoft.Maui.Devices.Sensors.Location!
+Microsoft.Maui.Devices.Sensors.GeolocationLocationChangedEventArgs.GeolocationLocationChangedEventArgs(Microsoft.Maui.Devices.Sensors.Location! location) -> void
+static Microsoft.Maui.Devices.Sensors.Geolocation.IsListeningForeground.get -> bool
+static Microsoft.Maui.Devices.Sensors.Geolocation.LocationChanged -> System.EventHandler!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StartListeningForegroundAsync(Microsoft.Maui.Devices.Sensors.GeolocationListeningRequest! request) -> System.Threading.Tasks.Task!
+static Microsoft.Maui.Devices.Sensors.Geolocation.StopListeningForeground() -> void
+*REMOVED*static Microsoft.Maui.ApplicationModel.Communication.PhoneDialer.Current.get -> Microsoft.Maui.ApplicationModel.Communication.IPhoneDialer!
diff --git a/src/Essentials/src/Sms/Sms.netstandard.tvos.watchos.cs b/src/Essentials/src/Sms/Sms.netstandard.tvos.watchos.cs
index 73146b23d8c5..7ba40e44818a 100644
--- a/src/Essentials/src/Sms/Sms.netstandard.tvos.watchos.cs
+++ b/src/Essentials/src/Sms/Sms.netstandard.tvos.watchos.cs
@@ -2,7 +2,6 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
- ///
partial class SmsImplementation : ISms
{
public bool IsComposeSupported
diff --git a/src/Essentials/src/Sms/Sms.shared.cs b/src/Essentials/src/Sms/Sms.shared.cs
index 4510353c648a..c719f4fda509 100644
--- a/src/Essentials/src/Sms/Sms.shared.cs
+++ b/src/Essentials/src/Sms/Sms.shared.cs
@@ -5,21 +5,42 @@
namespace Microsoft.Maui.ApplicationModel.Communication
{
+ ///
+ /// The SMS API enables an application to open the default SMS application with a specified message to send to a recipient.
+ ///
public interface ISms
{
+ ///
+ /// Gets a value indicating whether composing of SMS messages is supported on this device.
+ ///
bool IsComposeSupported { get; }
+ ///
+ /// Opens the default SMS client to allow the user to send the message.
+ ///
+ /// A instance with information about the message to send.
+ /// A object with the current status of the asynchronous operation.
Task ComposeAsync(SmsMessage? message);
}
- ///
+ ///
+ /// The SMS API enables an application to open the default SMS application with a specified message to send to a recipient.
+ ///
+ /// When using this on Android targeting Android 11 (R API 30) you must update your Android Manifest with queries that are used with the new package visibility requirements. See the conceptual docs for more information.
public static class Sms
{
- ///
+ ///
+ /// Opens the default SMS client to allow the user to send the message.
+ ///
+ /// A object with the current status of the asynchronous operation.
public static Task ComposeAsync()
=> Current.ComposeAsync(null);
- ///
+ ///
+ /// Opens the default SMS client to allow the user to send the message.
+ ///
+ /// A instance with information about the message to send.
+ /// A object with the current status of the asynchronous operation.
public static Task ComposeAsync(SmsMessage? message)
=> Current.ComposeAsync(message);
@@ -27,6 +48,9 @@ public static Task ComposeAsync(SmsMessage? message)
static ISms? defaultImplementation;
+ ///
+ /// Provides the default implementation for static usage of this API.
+ ///
public static ISms Default =>
defaultImplementation ??= new SmsImplementation();
@@ -52,15 +76,23 @@ public Task ComposeAsync(SmsMessage? message)
}
}
- ///
+ ///
+ /// Represents a single SMS message.
+ ///
public class SmsMessage
{
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
public SmsMessage()
{
}
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The body text that is used to prefill the composed SMS message.
+ /// A single recipient that is added to the composed SMS message.
public SmsMessage(string body, string? recipient)
{
Body = body;
@@ -68,7 +100,12 @@ public SmsMessage(string body, string? recipient)
Recipients.Add(recipient!);
}
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The body text that is used to prefill the composed SMS message.
+ /// A collection of recipients that are added to the composed SMS message.
+ /// Values in that are or whitespace are not added as recipients.
public SmsMessage(string body, IEnumerable? recipients)
{
Body = body;
@@ -78,10 +115,14 @@ public SmsMessage(string body, IEnumerable? recipients)
}
}
- ///
+ ///
+ /// Gets or sets the body of this message.
+ ///
public string? Body { get; set; }
- ///
+ ///
+ /// Gets or sets the recipients for this message.
+ ///
public List Recipients { get; set; } = new List();
}
}
diff --git a/src/Essentials/src/Types/DeviceIdiom.shared.cs b/src/Essentials/src/Types/DeviceIdiom.shared.cs
index 99f29651ce4f..851a5e1de8d0 100644
--- a/src/Essentials/src/Types/DeviceIdiom.shared.cs
+++ b/src/Essentials/src/Types/DeviceIdiom.shared.cs
@@ -2,27 +2,41 @@
namespace Microsoft.Maui.Devices
{
- ///
+ ///
+ /// Represents the idiom (form factor) of the device.
+ ///
public readonly struct DeviceIdiom : IEquatable
{
readonly string deviceIdiom;
- ///
+ ///
+ /// Gets an instance of that represents a (mobile) phone idiom.
+ ///
public static DeviceIdiom Phone { get; } = new DeviceIdiom(nameof(Phone));
- ///
+ ///
+ /// Gets an instance of that represents a tablet idiom.
+ ///
public static DeviceIdiom Tablet { get; } = new DeviceIdiom(nameof(Tablet));
- ///
+ ///
+ /// Gets an instance of that represents a desktop computer idiom.
+ ///
public static DeviceIdiom Desktop { get; } = new DeviceIdiom(nameof(Desktop));
- ///
+ ///
+ /// Gets an instance of that represents a television (TV) idiom.
+ ///
public static DeviceIdiom TV { get; } = new DeviceIdiom(nameof(TV));
- ///
+ ///
+ /// Gets an instance of that represents a watch idiom.
+ ///
public static DeviceIdiom Watch { get; } = new DeviceIdiom(nameof(Watch));
- ///
+ ///
+ /// Gets an instance of that represents an unknown idiom. This is used for when the current device idiom is unknown.
+ ///
public static DeviceIdiom Unknown { get; } = new DeviceIdiom(nameof(Unknown));
DeviceIdiom(string deviceIdiom)
@@ -36,22 +50,33 @@ namespace Microsoft.Maui.Devices
this.deviceIdiom = deviceIdiom;
}
- ///
+ ///
+ /// Creates a new device idiom instance. This can be used to define your custom idioms.
+ ///
+ /// The idiom name of the device.
+ /// A new instance of with the specified idiom type.
public static DeviceIdiom Create(string deviceIdiom) =>
new DeviceIdiom(deviceIdiom);
- ///
+ ///
+ /// Compares the underlying instances.
+ ///
+ /// object to compare with.
+ /// if they are equal, otherwise .
public bool Equals(DeviceIdiom other) =>
Equals(other.deviceIdiom);
internal bool Equals(string other) =>
string.Equals(deviceIdiom, other, StringComparison.Ordinal);
- ///
+ ///
public override bool Equals(object obj) =>
obj is DeviceIdiom && Equals((DeviceIdiom)obj);
- ///
+ ///
+ /// Gets the hash code for this idiom instance.
+ ///
+ /// The computed hash code for this device idiom or 0 when the device idiom is .
public override int GetHashCode() =>
deviceIdiom == null ? 0 : deviceIdiom.GetHashCode(
#if !NETSTANDARD2_0
@@ -59,13 +84,28 @@ public override int GetHashCode() =>
#endif
);
- ///
+ ///
+ /// Returns a string representation of the current value of .
+ ///
+ /// A string representation of this instance in the format of {device idiom} or an empty string when no device idiom is set.
public override string ToString() =>
deviceIdiom ?? string.Empty;
+ ///
+ /// Equality operator for equals.
+ ///
+ /// Left to compare.
+ /// Right to compare.
+ /// if objects are equal, otherwise .
public static bool operator ==(DeviceIdiom left, DeviceIdiom right) =>
left.Equals(right);
+ ///
+ /// Inequality operator.
+ ///
+ /// Left to compare.
+ /// Right to compare.
+ /// if objects are not equal, otherwise .
public static bool operator !=(DeviceIdiom left, DeviceIdiom right) =>
!left.Equals(right);
}
diff --git a/src/Essentials/src/Types/DevicePlatform.shared.cs b/src/Essentials/src/Types/DevicePlatform.shared.cs
index 974ac523148f..c4c1031579e2 100644
--- a/src/Essentials/src/Types/DevicePlatform.shared.cs
+++ b/src/Essentials/src/Types/DevicePlatform.shared.cs
@@ -2,38 +2,64 @@
namespace Microsoft.Maui.Devices
{
- ///
+ ///
+ /// Represents the device platform that the application is running on.
+ ///
public readonly struct DevicePlatform : IEquatable
{
readonly string devicePlatform;
- ///
+ ///
+ /// Gets an instance of that represents Android.
+ ///
public static DevicePlatform Android { get; } = new DevicePlatform(nameof(Android));
- ///
+ ///
+ /// Gets an instance of that represents iOS.
+ ///
public static DevicePlatform iOS { get; } = new DevicePlatform(nameof(iOS));
- ///
+ ///
+ /// Gets an instance of that represents macOS.
+ ///
+ /// Note, this is different than .
public static DevicePlatform macOS { get; } = new DevicePlatform(nameof(macOS));
+ ///
+ /// Gets an instance of that represents Mac Catalyst.
+ ///
+ /// Note, this is different than .
public static DevicePlatform MacCatalyst { get; } = new DevicePlatform(nameof(MacCatalyst));
- ///
+ ///
+ /// Gets an instance of that represents Apple tvOS.
+ ///
public static DevicePlatform tvOS { get; } = new DevicePlatform(nameof(tvOS));
- ///
+ ///
+ /// Gets an instance of that represents Samsung Tizen.
+ ///
public static DevicePlatform Tizen { get; } = new DevicePlatform(nameof(Tizen));
- ///
+ ///
+ /// Gets an instance of that represents UWP.
+ ///
[Obsolete("Use WinUI instead.")]
public static DevicePlatform UWP { get; } = new DevicePlatform(nameof(WinUI));
+ ///
+ /// Gets an instance of that represents WinUI.
+ ///
public static DevicePlatform WinUI { get; } = new DevicePlatform(nameof(WinUI));
- ///
+ ///
+ /// Gets an instance of that represents Apple watchOS.
+ ///
public static DevicePlatform watchOS { get; } = new DevicePlatform(nameof(watchOS));
- ///
+ ///
+ /// Gets an instance of that represents an unknown platform. This is used for when the current platform is unknown.
+ ///
public static DevicePlatform Unknown { get; } = new DevicePlatform(nameof(Unknown));
DevicePlatform(string devicePlatform)
@@ -47,22 +73,33 @@ namespace Microsoft.Maui.Devices
this.devicePlatform = devicePlatform;
}
- ///
+ ///
+ /// Creates a new device platform instance. This can be used to define your custom platforms.
+ ///
+ /// The device platform identifier.
+ /// A new instance of with the specified platform identifier.
public static DevicePlatform Create(string devicePlatform) =>
new DevicePlatform(devicePlatform);
- ///
+ ///
+ /// Compares the underlying instances.
+ ///
+ /// object to compare with.
+ /// if they are equal, otherwise .
public bool Equals(DevicePlatform other) =>
Equals(other.devicePlatform);
internal bool Equals(string other) =>
string.Equals(devicePlatform, other, StringComparison.Ordinal);
- ///
+ ///
public override bool Equals(object obj) =>
obj is DevicePlatform && Equals((DevicePlatform)obj);
- ///
+ ///
+ /// Gets the hash code for this platform instance.
+ ///
+ /// The computed hash code for this device platform or 0 when the device platform is .
public override int GetHashCode() =>
devicePlatform == null ? 0 : devicePlatform.GetHashCode(
#if !NETSTANDARD2_0
@@ -70,13 +107,28 @@ public override int GetHashCode() =>
#endif
);
- ///
+ ///
+ /// Returns a string representation of the current value of .
+ ///
+ /// A string representation of this instance in the format of {device platform} or an empty string when no device platform is set.
public override string ToString() =>
devicePlatform ?? string.Empty;
+ ///
+ /// Equality operator for equals.
+ ///
+ /// Left to compare.
+ /// Right to compare.
+ /// if objects are equal, otherwise .
public static bool operator ==(DevicePlatform left, DevicePlatform right) =>
left.Equals(right);
+ ///
+ /// Inequality operator.
+ ///
+ /// Left to compare.
+ /// Right to compare.
+ /// if objects are not equal, otherwise .
public static bool operator !=(DevicePlatform left, DevicePlatform right) =>
!left.Equals(right);
}
diff --git a/src/Essentials/src/Types/DisplayInfo.shared.cs b/src/Essentials/src/Types/DisplayInfo.shared.cs
index 2a931a4ebfff..2cfa915f7c01 100644
--- a/src/Essentials/src/Types/DisplayInfo.shared.cs
+++ b/src/Essentials/src/Types/DisplayInfo.shared.cs
@@ -3,10 +3,19 @@
namespace Microsoft.Maui.Devices
{
- ///
+ ///
+ /// Represents information about the device's screen.
+ ///
public readonly struct DisplayInfo : IEquatable
{
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The width of the display.
+ /// The height of the display.
+ /// The screen density.
+ /// The current orientation.
+ /// The rotation of the device.
public DisplayInfo(double width, double height, double density, DisplayOrientation orientation, DisplayRotation rotation)
{
Width = width;
@@ -17,7 +26,15 @@ public DisplayInfo(double width, double height, double density, DisplayOrientati
RefreshRate = 0;
}
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The width of the display.
+ /// The height of the display.
+ /// The screen density.
+ /// The current orientation.
+ /// The rotation of the device.
+ /// The refresh rate of the display.
public DisplayInfo(double width, double height, double density, DisplayOrientation orientation, DisplayRotation rotation, float rate)
{
Width = width;
@@ -28,35 +45,69 @@ public DisplayInfo(double width, double height, double density, DisplayOrientati
RefreshRate = rate;
}
- ///
+ ///
+ /// Gets the width of the screen (in pixels) for the current .
+ ///
public double Width { get; }
- ///
+ ///
+ /// Gets the height of the screen (in pixels) for the current .
+ ///
public double Height { get; }
- ///
+ ///
+ /// Gets a value representing the screen density.
+ ///
+ ///
+ /// The density is the scaling or a factor that can be used to convert between physical pixels and scaled pixels. For example, on high resolution displays, the physical number of pixels increases, but the scaled pixels remain the same.
+ /// In a practical example for iOS, the Retina display will have a density of 2.0 or 3.0, but the units used to lay out a view does not change much. A view with a UI width of 100 may be 100 physical pixels (density = 1) on a non-Retina device, but be 200 physical pixels (density = 2) on a Retina device.
+ /// On Windows, the density works similarly, and may often relate to the scale used in the display. On some monitors, the scale is set to 100% (density = 1), but on other high resolution monitors, the scale may be set to 200% (density = 2) or even 250% (density = 2.5).
+ ///
public double Density { get; }
- ///
+ ///
+ /// Gets the orientation of the device's display.
+ ///
public DisplayOrientation Orientation { get; }
- ///
+ ///
+ /// Gets the orientation of the device's display.
+ ///
public DisplayRotation Rotation { get; }
- ///
+ ///
+ /// Gets the refresh rate (in Hertz) of the device's display.
+ ///
public float RefreshRate { get; }
+ ///
+ /// Equality operator for equals.
+ ///
+ /// Left to compare.
+ /// Right to compare.
+ /// if objects are equal, otherwise .
public static bool operator ==(DisplayInfo left, DisplayInfo right) =>
left.Equals(right);
+ ///
+ /// Inequality operator.
+ ///
+ /// Left to compare.
+ /// Right to compare.
+ /// if objects are not equal, otherwise .
public static bool operator !=(DisplayInfo left, DisplayInfo right) =>
!left.Equals(right);
- ///
+ ///
public override bool Equals(object obj) =>
(obj is DisplayInfo metrics) && Equals(metrics);
- ///
+ ///
+ /// Compares the underlying instances.
+ ///
+ /// object to compare with.
+ /// if they are equal, otherwise .
+ /// Equality is established by comparing if , , , and are all equal.
public bool Equals(DisplayInfo other) =>
Width.Equals(other.Width) &&
Height.Equals(other.Height) &&
@@ -64,11 +115,18 @@ public bool Equals(DisplayInfo other) =>
Orientation.Equals(other.Orientation) &&
Rotation.Equals(other.Rotation);
- ///
+ ///
+ /// Gets the hash code for this display info instance.
+ ///
+ /// The computed hash code for this device idiom or 0 when the device platform is .
+ /// The hash code is computed from , , , and .
public override int GetHashCode() =>
(Height, Width, Density, Orientation, Rotation).GetHashCode();
- ///
+ ///
+ /// Returns a string representation of the current values of this display info instance.
+ ///
+ /// A string representation of this instance in the format of Height: {value}, Width: {value}, Density: {value}, Orientation: {value}, Rotation: {value}.
public override string ToString() =>
$"{nameof(Height)}: {Height}, {nameof(Width)}: {Width}, " +
$"{nameof(Density)}: {Density}, {nameof(Orientation)}: {Orientation}, " +
diff --git a/src/Essentials/src/Types/DisplayOrientation.shared.cs b/src/Essentials/src/Types/DisplayOrientation.shared.cs
index 6f34c0afa86d..4b812b545b5f 100644
--- a/src/Essentials/src/Types/DisplayOrientation.shared.cs
+++ b/src/Essentials/src/Types/DisplayOrientation.shared.cs
@@ -1,13 +1,17 @@
namespace Microsoft.Maui.Devices
{
- ///
+ ///
+ /// Represents the orientation a device display can have.
+ ///
public enum DisplayOrientation
{
- ///
+ /// Unknown display orientation.
Unknown = 0,
- ///
+
+ /// Device display is in portrait orientation.
Portrait = 1,
- ///
+
+ /// Device display is in landscape orientation.
Landscape = 2
}
}
diff --git a/src/Essentials/src/Types/DisplayRotation.shared.cs b/src/Essentials/src/Types/DisplayRotation.shared.cs
index 1e7cf549a819..6905c10f5138 100644
--- a/src/Essentials/src/Types/DisplayRotation.shared.cs
+++ b/src/Essentials/src/Types/DisplayRotation.shared.cs
@@ -1,17 +1,23 @@
namespace Microsoft.Maui.Devices
{
- ///
+ ///
+ /// Represents the rotation a device display can have.
+ ///
public enum DisplayRotation
{
- ///
+ /// Unknown display rotation.
Unknown = 0,
- ///
+
+ /// The device display is rotated 0 degrees.
Rotation0 = 1,
- ///
+
+ /// The device display is rotated 90 degrees.
Rotation90 = 2,
- ///
+
+ /// The device display is rotated 180 degrees.
Rotation180 = 3,
- ///
+
+ /// The device display is rotated 270 degrees.
Rotation270 = 4
}
}
diff --git a/src/Essentials/src/Types/Location.shared.cs b/src/Essentials/src/Types/Location.shared.cs
index 16a54d5a7121..efb282111e09 100644
--- a/src/Essentials/src/Types/Location.shared.cs
+++ b/src/Essentials/src/Types/Location.shared.cs
@@ -243,6 +243,7 @@ public override string ToString() =>
$"{nameof(Course)}: {Course}, " +
$"{nameof(Timestamp)}: {Timestamp}";
+ ///
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
@@ -253,6 +254,7 @@ public override bool Equals(object obj)
return Latitude == other.Latitude && Longitude == other.Longitude;
}
+ ///
public override int GetHashCode()
{
unchecked
diff --git a/src/Essentials/src/Types/LocationExtensions.shared.cs b/src/Essentials/src/Types/LocationExtensions.shared.cs
index 6cab479284d8..137ee87510c7 100644
--- a/src/Essentials/src/Types/LocationExtensions.shared.cs
+++ b/src/Essentials/src/Types/LocationExtensions.shared.cs
@@ -4,22 +4,24 @@
namespace Microsoft.Maui.Devices.Sensors
{
- ///
+ ///
+ /// This class contains static extension methods for use with objects.
+ ///
public static partial class LocationExtensions
{
- ///
+ ///
public static double CalculateDistance(this Location locationStart, double latitudeEnd, double longitudeEnd, DistanceUnits units) =>
Location.CalculateDistance(locationStart, latitudeEnd, longitudeEnd, units);
- ///
+ ///
public static double CalculateDistance(this Location locationStart, Location locationEnd, DistanceUnits units) =>
Location.CalculateDistance(locationStart, locationEnd, units);
- ///
+ ///
public static Task OpenMapsAsync(this Location location, MapLaunchOptions options) =>
Map.OpenAsync(location, options);
- ///
+ ///
public static Task OpenMapsAsync(this Location location) =>
Map.OpenAsync(location);
}
diff --git a/src/Essentials/src/Types/Placemark.shared.cs b/src/Essentials/src/Types/Placemark.shared.cs
index a01c8f0fa1b2..fbb71dcedcde 100644
--- a/src/Essentials/src/Types/Placemark.shared.cs
+++ b/src/Essentials/src/Types/Placemark.shared.cs
@@ -2,15 +2,23 @@
namespace Microsoft.Maui.Devices.Sensors
{
- ///
+ ///
+ /// Represents a user-friendly description of a geographic coordinate. This contains information such as the name of the place, its address, and other information.
+ ///
public class Placemark
{
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
public Placemark()
{
}
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An instance of that will be used to clone into this instance.
+ /// Thrown when is .
public Placemark(Placemark placemark)
{
if (placemark == null)
@@ -33,40 +41,65 @@ public Placemark(Placemark placemark)
AdminArea = placemark.AdminArea;
}
- ///
+ ///
+ /// Gets or sets the location of the placemark.
+ ///
public Location Location { get; set; }
- ///
+ ///
+ /// Gets or sets the country ISO standard code.
+ ///
public string CountryCode { get; set; }
- ///
+ ///
+ /// Gets or sets the country name.
+ ///
public string CountryName { get; set; }
- ///
+ ///
+ /// Gets or sets the feature name.
+ ///
public string FeatureName { get; set; }
- ///
+ ///
+ /// Gets or sets the postal code.
+ ///
public string PostalCode { get; set; }
- ///
+ ///
+ /// Gets or sets the sub locality.
+ ///
public string SubLocality { get; set; }
- ///
+ ///
+ /// Gets or sets the street name.
+ ///
public string Thoroughfare { get; set; }
- ///
+ ///
+ /// Gets or sets optional info: sub street or region.
+ ///
public string SubThoroughfare { get; set; }
- ///
+ ///
+ /// Gets or sets the city or town.
+ ///
public string Locality { get; set; }
- ///
+ ///
+ /// Gets or sets the administrative area name of the address, for example, "CA", or if it is unknown.
+ ///
public string AdminArea { get; set; }
- ///
+ ///
+ /// Gets or sets the sub-administrative area name of the address, for example, "Santa Clara County", or if it is unknown.
+ ///
public string SubAdminArea { get; set; }
- ///
+ ///
+ /// Returns a string representation of the current values of .
+ ///
+ /// A string representation of this instance in the format of Location: {value}, CountryCode: {value}, CountryName: {value}, FeatureName: {value}, PostalCode: {value}, SubLocality: {value}, Thoroughfare: {value}, SubThoroughfare: {value}, Locality: {value}, AdminArea: {value}, SubAdminArea: {value}.
public override string ToString() =>
$"{nameof(Location)}: {Location}, {nameof(CountryCode)}: {CountryCode}, " +
$"{nameof(CountryName)}: {CountryName}, {nameof(FeatureName)}: {FeatureName}, " +
diff --git a/src/Essentials/src/Types/PlacemarkExtensions.shared.cs b/src/Essentials/src/Types/PlacemarkExtensions.shared.cs
index 3d37a7915295..a7e48ea312f6 100644
--- a/src/Essentials/src/Types/PlacemarkExtensions.shared.cs
+++ b/src/Essentials/src/Types/PlacemarkExtensions.shared.cs
@@ -4,14 +4,16 @@
namespace Microsoft.Maui.Devices.Sensors
{
- ///
+ ///
+ /// This class contains static extension methods for use with objects.
+ ///
public static partial class PlacemarkExtensions
{
- ///
+ ///
public static Task OpenMapsAsync(this Placemark placemark, MapLaunchOptions options) =>
Map.OpenAsync(placemark, options);
- ///
+ ///
public static Task OpenMapsAsync(this Placemark placemark) =>
Map.OpenAsync(placemark);
diff --git a/src/Essentials/src/Types/SensorSpeed.shared.cs b/src/Essentials/src/Types/SensorSpeed.shared.cs
index 46db52b4896c..051d09d09e4e 100644
--- a/src/Essentials/src/Types/SensorSpeed.shared.cs
+++ b/src/Essentials/src/Types/SensorSpeed.shared.cs
@@ -1,15 +1,20 @@
namespace Microsoft.Maui.Devices.Sensors
{
- ///
+ ///
+ /// Represents the sensor speed to monitor device sensors for changes.
+ ///
public enum SensorSpeed
{
- ///
+ /// The device default sensor speed.
Default = 0,
- ///
+
+ /// Rate suitable for general user interface.
UI = 1,
- ///
+
+ /// Rate suitable for games.
Game = 2,
- ///
+
+ /// Get the sensor data as fast as possible.
Fastest = 3,
}
}
diff --git a/src/Essentials/src/UnitConverters/UnitConverters.shared.cs b/src/Essentials/src/UnitConverters/UnitConverters.shared.cs
index 89b42e10ca24..d042d39069a0 100644
--- a/src/Essentials/src/UnitConverters/UnitConverters.shared.cs
+++ b/src/Essentials/src/UnitConverters/UnitConverters.shared.cs
@@ -2,7 +2,9 @@
namespace Microsoft.Maui.Media
{
- ///
+ ///
+ /// Static class with built-in unit converters.
+ ///
public static class UnitConverters
{
const double twoPi = 2.0 * Math.PI;
@@ -23,111 +25,225 @@ public static class UnitConverters
const double internationalFootDefinition = 0.3048;
const double usSurveyFootDefinition = 1200.0 / 3937;
- ///
+ ///
+ /// Converts temperatures from Fahrenheit to Celsius.
+ ///
+ /// The value in Fahrenheit to convert.
+ /// The value from in degrees Celsius.
public static double FahrenheitToCelsius(double fahrenheit) =>
(fahrenheit - 32.0) / 1.8;
- ///
+ ///
+ /// Converts temperatures from Celsius to Fahrenheit.
+ ///
+ /// The value in Celcius to convert.
+ /// The value from in degrees Fahrenheit.
public static double CelsiusToFahrenheit(double celsius) =>
celsius * 1.8 + 32.0;
- ///
+ ///
+ /// Converts temperatures from Celsius to Kelvin.
+ ///
+ /// The value in Celcius to convert.
+ /// The value from in degrees Kelvin.
public static double CelsiusToKelvin(double celsius) =>
celsius + celsiusToKelvin;
- ///
+ ///
+ /// Converts temperatures from Kelvin to Celsius.
+ ///
+ /// The value in Kelvin to convert.
+ /// The value from in degrees Celcius.
public static double KelvinToCelsius(double kelvin) =>
kelvin - celsiusToKelvin;
- ///
+ ///
+ /// Converts distances from miles to meters.
+ ///
+ /// The value in miles to convert.
+ /// The value from in meters.
public static double MilesToMeters(double miles) =>
miles * milesToMeters;
- ///
+ ///
+ /// Converts distances from miles to kilometers.
+ ///
+ /// The value in miles to convert.
+ /// The value from in kilometers.
public static double MilesToKilometers(double miles) =>
miles * milesToKilometers;
- ///
+ ///
+ /// Converts distances from kilometers to miles.
+ ///
+ /// The value in kilometers to convert.
+ /// The value from in miles.
public static double KilometersToMiles(double kilometers) =>
kilometers * kilometersToMiles;
- ///
+ ///
+ /// Converts degrees to radian.
+ ///
+ /// The value in degrees to convert.
+ /// The value from in radian.
public static double DegreesToRadians(double degrees) =>
degrees * degreesToRadians;
- ///
+ ///
+ /// Converts radians to degrees.
+ ///
+ /// The value in radians to convert.
+ /// The value from in degrees.
public static double RadiansToDegrees(double radians) =>
radians / degreesToRadians;
- ///
+ ///
+ /// Converts pounds to kilograms.
+ ///
+ /// The value in pounds to convert.
+ /// The value from in kilograms.
public static double PoundsToKilograms(double pounds) =>
pounds * poundsToKg;
- ///
+ ///
+ /// Converts pounds to stones.
+ ///
+ /// The value in pounds to convert.
+ /// The value from in stones.
public static double PoundsToStones(double pounds) =>
pounds * poundsToStones;
- ///
+ ///
+ /// Converts stones to pounds.
+ ///
+ /// The value in stones to convert.
+ /// The value from in pounds.
public static double StonesToPounds(double stones) =>
stones * stonesToPounds;
- ///
+ ///
+ /// Converts kilograms to pounds.
+ ///
+ /// The value in kilograms to convert.
+ /// The value from in pounds.
public static double KilogramsToPounds(double kilograms) =>
kilograms * kgToPounds;
- ///
+ ///
+ /// Converts degrees per second to radians per second.
+ ///
+ /// The value in degrees per second to convert.
+ /// The value from in radians per second.
public static double DegreesPerSecondToRadiansPerSecond(double degrees) =>
HertzToRadiansPerSecond(DegreesPerSecondToHertz(degrees));
- ///
+ ///
+ /// Converts radians per second to degrees per second.
+ ///
+ /// The value in radians per second to convert.
+ /// The value from in degrees per second.
public static double RadiansPerSecondToDegreesPerSecond(double radians) =>
HertzToDegreesPerSecond(RadiansPerSecondToHertz(radians));
- ///
+ ///
+ /// Converts degrees per second to hertz.
+ ///
+ /// The value in degrees per second to convert.
+ /// The value from in hertz.
public static double DegreesPerSecondToHertz(double degrees) =>
degrees / totalDegrees;
- ///
+ ///
+ /// Converts radians per second to hertz.
+ ///
+ /// The value in radians per second to convert.
+ /// The value from in hertz.
public static double RadiansPerSecondToHertz(double radians) =>
radians / twoPi;
- ///
+ ///
+ /// Converts hertz to degrees per second.
+ ///
+ /// The value in degrees per second to convert.
+ /// The value from in degrees per second.
public static double HertzToDegreesPerSecond(double hertz) =>
hertz * totalDegrees;
- ///
+ ///
+ /// Converts hertz to radians per second.
+ ///
+ /// The value in radians per second to convert.
+ /// The value from in radians per second.
public static double HertzToRadiansPerSecond(double hertz) =>
hertz * twoPi;
- ///
+ ///
+ /// Converts Kilopascals to Hectopascals.
+ ///
+ /// The value in Kilopascals convert.
+ /// The value from in Hectopascals.
public static double KilopascalsToHectopascals(double kpa) =>
kpa * 10.0;
- ///
+ ///
+ /// Converts Kilopascals to Hectopascals.
+ ///
+ /// The value in Hectopascals convert.
+ /// The value from in Kilopascals.
public static double HectopascalsToKilopascals(double hpa) =>
hpa / 10.0;
- ///
+ ///
+ /// Converts Kilopascals to Pascals.
+ ///
+ /// The value in Kilopascals convert.
+ /// The value from in Pascals.
public static double KilopascalsToPascals(double kpa) =>
kpa * 1000.0;
- ///
+ ///
+ /// Converts Hectopascals to Pascals.
+ ///
+ /// The value in Hectopascals convert.
+ /// The value from in Pascals.
public static double HectopascalsToPascals(double hpa) =>
hpa * 100.0;
- ///
+ ///
+ /// Converts Atmospheres to Pascals.
+ ///
+ /// The value in Atmospheres convert.
+ /// The value from in Pascals.
public static double AtmospheresToPascals(double atm) =>
atm * atmospherePascals;
- ///
+ ///
+ /// Converts Pascals to Atmospheres.
+ ///
+ /// The value in Pascals convert.
+ /// The value from in Atmospheres.
public static double PascalsToAtmospheres(double pascals) =>
pascals / atmospherePascals;
- ///
+ ///
+ /// Calculates the distance between two coordinates in miles.
+ ///
+ /// First latitude.
+ /// First longitude.
+ /// Second latitude.
+ /// Second longitude.
+ /// The distance in miles.
public static double CoordinatesToMiles(double lat1, double lon1, double lat2, double lon2) =>
KilometersToMiles(CoordinatesToKilometers(lat1, lon1, lat2, lon2));
- ///
+ ///
+ /// Calculates the distance between two coordinates in kilometers.
+ ///
+ /// First latitude.
+ /// First longitude.
+ /// Second latitude.
+ /// Second longitude.
+ /// The distance in kilometers.
public static double CoordinatesToKilometers(double lat1, double lon1, double lat2, double lon2)
{
if (lat1 == lat2 && lon1 == lon2)
diff --git a/src/Essentials/src/WebAuthenticator/AppleSignInAuthenticator.shared.cs b/src/Essentials/src/WebAuthenticator/AppleSignInAuthenticator.shared.cs
index 52e684955635..858c02fc400a 100644
--- a/src/Essentials/src/WebAuthenticator/AppleSignInAuthenticator.shared.cs
+++ b/src/Essentials/src/WebAuthenticator/AppleSignInAuthenticator.shared.cs
@@ -3,30 +3,57 @@
namespace Microsoft.Maui.Authentication
{
+ ///
+ /// Represents platform native Apple Sign In authentication APIs.
+ ///
public interface IAppleSignInAuthenticator
{
+ ///
+ /// Performs a native Apple Sign In authentication request.
+ ///
+ /// Additional Sign In options.
+ /// A object with the results of this operation.
Task AuthenticateAsync(AppleSignInAuthenticator.Options? options = null);
}
- ///
+ ///
+ /// Represents platform native Apple Sign In authentication APIs.
+ ///
+ /// This API is only supported on iOS 13.0+ and should not be called on other devices at runtime.
public static class AppleSignInAuthenticator
{
- ///
+ ///
+ /// Performs a native Apple Sign In authentication request.
+ ///
+ /// Additional Sign In options.
+ /// A object with the results of this operation.
public static Task AuthenticateAsync(AppleSignInAuthenticator.Options? options = null)
=> Default.AuthenticateAsync(options ?? new AppleSignInAuthenticator.Options());
static IAppleSignInAuthenticator? defaultImplementation;
+ ///
+ /// Provides the default implementation for static usage of this API.
+ ///
public static IAppleSignInAuthenticator Default =>
defaultImplementation ??= new AppleSignInAuthenticatorImplementation();
internal static void SetDefault(IAppleSignInAuthenticator? implementation) =>
defaultImplementation = implementation;
+ ///
+ /// Represents additional options for Apple Sign In.
+ ///
public class Options
{
+ ///
+ /// Gets or sets whether to request the full name scope during sign in.
+ ///
public bool IncludeFullNameScope { get; set; } = false;
+ ///
+ /// Gets or sets whether to request the email scope during sign in.
+ ///
public bool IncludeEmailScope { get; set; } = false;
}
}
diff --git a/src/Essentials/src/WebAuthenticator/WebAuthenticator.android.cs b/src/Essentials/src/WebAuthenticator/WebAuthenticator.android.cs
index 91ade546c64b..f66c15692180 100644
--- a/src/Essentials/src/WebAuthenticator/WebAuthenticator.android.cs
+++ b/src/Essentials/src/WebAuthenticator/WebAuthenticator.android.cs
@@ -11,6 +11,7 @@ partial class WebAuthenticatorImplementation : IWebAuthenticator, IPlatformWebAu
{
TaskCompletionSource tcsResponse = null;
Uri currentRedirectUri = null;
+ WebAuthenticatorOptions currentOptions = null;
public bool OnResumeCallback(Intent intent)
{
@@ -34,8 +35,7 @@ public bool OnResumeCallback(Intent intent)
tcsResponse.TrySetException(new InvalidOperationException($"Invalid Redirect URI, detected `{intentUri}` but expected a URI in the format of `{currentRedirectUri}`"));
return false;
}
-
- tcsResponse?.TrySetResult(new WebAuthenticatorResult(intentUri));
+ tcsResponse?.TrySetResult(new WebAuthenticatorResult(intentUri, currentOptions?.ResponseDecoder));
return true;
}
catch (Exception ex)
@@ -47,6 +47,7 @@ public bool OnResumeCallback(Intent intent)
public async Task AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions)
{
+ currentOptions = webAuthenticatorOptions;
var url = webAuthenticatorOptions?.Url;
var callbackUrl = webAuthenticatorOptions?.CallbackUrl;
var packageName = Application.Context.PackageName;
diff --git a/src/Essentials/src/WebAuthenticator/WebAuthenticator.ios.tvos.cs b/src/Essentials/src/WebAuthenticator/WebAuthenticator.ios.tvos.cs
index 50f160d73132..81169504e050 100644
--- a/src/Essentials/src/WebAuthenticator/WebAuthenticator.ios.tvos.cs
+++ b/src/Essentials/src/WebAuthenticator/WebAuthenticator.ios.tvos.cs
@@ -29,6 +29,7 @@ partial class WebAuthenticatorImplementation : IWebAuthenticator, IPlatformWebAu
TaskCompletionSource tcsResponse;
UIViewController currentViewController;
Uri redirectUri;
+ WebAuthenticatorOptions currentOptions;
#if __IOS__
ASWebAuthenticationSession was;
@@ -37,6 +38,7 @@ partial class WebAuthenticatorImplementation : IWebAuthenticator, IPlatformWebAu
public async Task AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions)
{
+ currentOptions = webAuthenticatorOptions;
var url = webAuthenticatorOptions?.Url;
var callbackUrl = webAuthenticatorOptions?.CallbackUrl;
var prefersEphemeralWebBrowserSession = webAuthenticatorOptions?.PrefersEphemeralWebBrowserSession ?? false;
@@ -167,11 +169,12 @@ public bool OpenUrlCallback(Uri uri)
currentViewController?.DismissViewControllerAsync(true);
currentViewController = null;
- tcsResponse.TrySetResult(new WebAuthenticatorResult(uri));
+ tcsResponse.TrySetResult(new WebAuthenticatorResult(uri, currentOptions?.ResponseDecoder));
return true;
}
catch (Exception ex)
{
+ // TODO change this to ILogger?
Console.WriteLine(ex);
}
return false;
diff --git a/src/Essentials/src/WebAuthenticator/WebAuthenticator.netstandard.watchos.tizen.cs b/src/Essentials/src/WebAuthenticator/WebAuthenticator.netstandard.watchos.tizen.cs
index ea76a2eced53..0f7697a23dbf 100644
--- a/src/Essentials/src/WebAuthenticator/WebAuthenticator.netstandard.watchos.tizen.cs
+++ b/src/Essentials/src/WebAuthenticator/WebAuthenticator.netstandard.watchos.tizen.cs
@@ -6,7 +6,6 @@
namespace Microsoft.Maui.Authentication
{
- ///
partial class WebAuthenticatorImplementation : IWebAuthenticator
{
public Task AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions)
diff --git a/src/Essentials/src/WebAuthenticator/WebAuthenticator.shared.cs b/src/Essentials/src/WebAuthenticator/WebAuthenticator.shared.cs
index e2ca34326aba..b67a0f050231 100644
--- a/src/Essentials/src/WebAuthenticator/WebAuthenticator.shared.cs
+++ b/src/Essentials/src/WebAuthenticator/WebAuthenticator.shared.cs
@@ -1,30 +1,78 @@
#nullable enable
using System;
+using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.Maui.Authentication
{
+ ///
+ /// A web navigation API intended to be used for authentication with external web services such as OAuth.
+ ///
public interface IWebAuthenticator
{
+ ///
+ /// Begin an authentication flow by navigating to the specified URL and waiting for a callback/redirect to the callback URL scheme.
+ ///
+ /// A instance containing additional configuration for this authentication call.
+ /// A object with the results of this operation.
Task AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions);
}
+ ///
+ /// Provides abstractions for the platform web authenticator callbacks triggered when using .
+ ///
public interface IPlatformWebAuthenticatorCallback
{
#if IOS || MACCATALYST || MACOS
+ ///
+ /// Opens the specified URI to start the authentication flow.
+ ///
+ /// The URI to open that will start the authentication flow.
+ /// when the URI has been opened, otherwise .
bool OpenUrlCallback(Uri uri);
#elif ANDROID
+ ///
+ /// The event that is triggered when an authentication flow calls back into the Android application.
+ ///
+ /// An object containing additional data about this resume operation.
+ /// when the callback can be processed, otherwise .
bool OnResumeCallback(Android.Content.Intent intent);
#endif
}
- ///
+ ///
+ /// Provides abstractions used for decoding a URI returned from a authentication request, for use with .
+ ///
+ public interface IWebAuthenticatorResponseDecoder
+ {
+ ///
+ /// Decodes the given URIs query string into a dictionary.
+ ///
+ /// The object to decode the query parameters from.
+ /// A object where each of the query parameters values of are accessible through their respective keys.
+ IDictionary? DecodeResponse(Uri uri);
+ }
+
+ ///
+ /// A web navigation API intended to be used for Authentication with external web services such as OAuth.
+ ///
+ ///
+ /// This API helps with navigating to a start URL and waiting for a callback URL to the app. Your app must
+ /// be registered to handle the callback scheme you provide in the call to authenticate.
+ ///
public static class WebAuthenticator
{
- ///
+ /// Begin an authentication flow by navigating to the specified url and waiting for a callback/redirect to the callbackUrl scheme.
+ /// Url to navigate to, beginning the authentication flow.
+ /// Expected callback url that the navigation flow will eventually redirect to.
+ /// Returns a result parsed out from the callback url.
public static Task AuthenticateAsync(Uri url, Uri callbackUrl)
=> Current.AuthenticateAsync(url, callbackUrl);
+ /// Begin an authentication flow by navigating to the specified url and waiting for a callback/redirect to the callbackUrl scheme.The start url and callbackUrl are specified in the webAuthenticatorOptions.
+ /// Options to configure the authentication request.
+ /// Returns a result parsed out from the callback url.
public static Task AuthenticateAsync(WebAuthenticatorOptions webAuthenticatorOptions)
=> Current.AuthenticateAsync(webAuthenticatorOptions);
@@ -32,6 +80,9 @@ public static Task AuthenticateAsync(WebAuthenticatorOpt
static IWebAuthenticator? defaultImplementation;
+ ///
+ /// Provides the default implementation for static usage of this API.
+ ///
public static IWebAuthenticator Default =>
defaultImplementation ??= new WebAuthenticatorImplementation();
@@ -39,6 +90,9 @@ internal static void SetDefault(IWebAuthenticator? implementation) =>
defaultImplementation = implementation;
}
+ ///
+ /// This class contains static extension methods for use with .
+ ///
public static class WebAuthenticatorExtensions
{
static IPlatformWebAuthenticatorCallback AsPlatformCallback(this IWebAuthenticator webAuthenticator)
@@ -48,14 +102,22 @@ static IPlatformWebAuthenticatorCallback AsPlatformCallback(this IWebAuthenticat
return platform;
}
+ ///
+ /// Begin an authentication flow by navigating to the specified url and waiting for a callback/redirect to the callbackUrl scheme.
+ ///
+ /// The to use for the authentication flow.
+ /// Url to navigate to, beginning the authentication flow.
+ /// Expected callback url that the navigation flow will eventually redirect to.
+ /// Returns a result parsed out from the callback url.
public static Task AuthenticateAsync(this IWebAuthenticator webAuthenticator, Uri url, Uri callbackUrl) =>
webAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions { Url = url, CallbackUrl = callbackUrl });
#if IOS || MACCATALYST || MACOS
-
+ ///
public static bool OpenUrl(this IWebAuthenticator webAuthenticator, Uri uri) =>
webAuthenticator.AsPlatformCallback().OpenUrlCallback(uri);
+ ///
public static bool OpenUrl(this IWebAuthenticator webAuthenticator, UIKit.UIApplication app, Foundation.NSUrl url, Foundation.NSDictionary options)
{
if(url?.AbsoluteString != null)
@@ -65,6 +127,7 @@ public static bool OpenUrl(this IWebAuthenticator webAuthenticator, UIKit.UIAppl
return false;
}
+ ///
public static bool ContinueUserActivity(this IWebAuthenticator webAuthenticator, UIKit.UIApplication application, Foundation.NSUserActivity userActivity, UIKit.UIApplicationRestorationHandler completionHandler)
{
var uri = userActivity?.WebPageUrl?.AbsoluteString;
@@ -75,19 +138,37 @@ public static bool ContinueUserActivity(this IWebAuthenticator webAuthenticator,
}
#elif ANDROID
-
+ ///
public static bool OnResume(this IWebAuthenticator webAuthenticator, Android.Content.Intent intent) =>
webAuthenticator.AsPlatformCallback().OnResumeCallback(intent);
-
#endif
}
+ ///
+ /// Represents additional options for .
+ ///
public class WebAuthenticatorOptions
{
+ ///
+ /// Gets or sets the URL that will start the authentication flow.
+ ///
public Uri? Url { get; set; }
+ ///
+ /// Gets or sets the callback URL that should be called when authentication completes.
+ ///
public Uri? CallbackUrl { get; set; }
+ ///
+ /// Gets or sets whether the browser used for the authentication flow is short-lived.
+ /// This means it will not share session nor cookies with the regular browser on this device if set the .
+ ///
+ /// This setting only has effect on iOS.
public bool PrefersEphemeralWebBrowserSession { get; set; }
+
+ ///
+ /// Gets or sets the decoder implementation used to decode the incoming authentication result URI.
+ ///
+ public IWebAuthenticatorResponseDecoder? ResponseDecoder { get; set; }
}
}
diff --git a/src/Essentials/src/WebAuthenticator/WebAuthenticator.uwp.cs b/src/Essentials/src/WebAuthenticator/WebAuthenticator.uwp.cs
index 164f4529c14c..8f233e9720cf 100644
--- a/src/Essentials/src/WebAuthenticator/WebAuthenticator.uwp.cs
+++ b/src/Essentials/src/WebAuthenticator/WebAuthenticator.uwp.cs
@@ -31,7 +31,7 @@ public async Task AuthenticateAsync(WebAuthenticatorOpti
case WebAuthenticationStatus.Success:
// For GET requests this is a URI:
var resultUri = new Uri(r.ResponseData.ToString());
- return new WebAuthenticatorResult(resultUri);
+ return new WebAuthenticatorResult(resultUri, webAuthenticatorOptions?.ResponseDecoder);
case WebAuthenticationStatus.UserCancel:
throw new TaskCanceledException();
case WebAuthenticationStatus.ErrorHttp:
diff --git a/src/Essentials/src/WebAuthenticator/WebAuthenticatorResult.shared.cs b/src/Essentials/src/WebAuthenticator/WebAuthenticatorResult.shared.cs
index 3a06a7e30e52..53a7ff72fb5a 100644
--- a/src/Essentials/src/WebAuthenticator/WebAuthenticatorResult.shared.cs
+++ b/src/Essentials/src/WebAuthenticator/WebAuthenticatorResult.shared.cs
@@ -1,46 +1,86 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Authentication
{
- ///
+ ///
+ /// Represents a Web Authenticator Result object parsed from the callback Url.
+ ///
+ ///
+ /// All of the query string or url fragment properties are parsed into a dictionary and can be accessed by their key.
+ ///
public class WebAuthenticatorResult
{
- ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
public WebAuthenticatorResult()
{
}
- ///
- public WebAuthenticatorResult(Uri uri)
+ ///
+ /// Initializes a new instance of the class by parsing a URI's query string parameters.
+ ///
+ /// The callback uri that was used to end the authentication sequence.
+ public WebAuthenticatorResult(Uri uri) : this(uri, null)
{
- foreach (var kvp in WebUtils.ParseQueryString(uri.ToString()))
+ }
+
+ ///
+ /// Initializes a new instance of the class by parsing a URI's query string parameters.
+ ///
+ ///
+ /// If the responseDecoder is non-null, then it is used to decode the fragment or query string
+ /// returned by the authorization service. Otherwise, a default response decoder is used.
+ ///
+ /// The callback uri that was used to end the authentication sequence.
+ /// The decoder that can be used to decode the callback uri.
+ public WebAuthenticatorResult(Uri uri, IWebAuthenticatorResponseDecoder responseDecoder)
+ {
+ CallbackUri = uri;
+ var properties = responseDecoder?.DecodeResponse(uri) ?? WebUtils.ParseQueryString(uri.ToString());
+ foreach (var kvp in properties)
{
Properties[kvp.Key] = kvp.Value;
}
}
- ///
+ ///
+ /// Create a new instance from an existing dictionary.
+ ///
+ /// The dictionary of properties to incorporate.
public WebAuthenticatorResult(IDictionary properties)
{
foreach (var kvp in properties)
Properties[kvp.Key] = kvp.Value;
}
- ///
+ ///
+ /// The uri that was used to call back with the access token.
+ ///
+ ///
+ /// The value of the callback URI, including the fragment or query string bearing
+ /// the access token and associated information.
+ ///
+ public Uri CallbackUri { get; }
+
+ ///
+ /// The timestamp when the class was instantiated, which usually corresponds with the parsed result of a request.
+ ///
public DateTimeOffset Timestamp { get; set; } = new DateTimeOffset(DateTime.UtcNow);
- ///
+ ///
+ /// The dictionary of key/value pairs parsed form the callback URI's query string.
+ ///
public Dictionary Properties { get; set; } = new Dictionary();
- ///
+ /// Puts a key/value pair into the dictionary.
public void Put(string key, string value)
=> Properties[key] = value;
- ///
+ /// Gets a value for a given key from the dictionary.
+ /// Key from the callback URI's query string.
public string Get(string key)
{
if (Properties.TryGetValue(key, out var v))
@@ -49,19 +89,27 @@ public string Get(string key)
return default;
}
- ///
+ /// The value for the `access_token` key.
+ /// Access Token parsed from the callback URI access_token parameter.
public string AccessToken
=> Get("access_token");
- ///
+ /// The value for the `refresh_token` key.
+ /// Refresh Token parsed from the callback URI refresh_token parameter.
public string RefreshToken
=> Get("refresh_token");
- ///
+ /// The value for the `id_token` key.
+ /// The value for the `id_token` key.
+ /// Apple doesn't return an access token on iOS native sign in, but it does return id_token as a JWT.
public string IdToken
=> Get("id_token");
- ///
+ ///
+ /// The refresh token expiry date as calculated by the timestamp of when the result was created plus
+ /// the value in seconds for the refresh_token_expires_in key.
+ ///
+ /// Timestamp of the creation of the object instance plus the expires_in seconds parsed from the callback URI.
public DateTimeOffset? RefreshTokenExpiresIn
{
get
@@ -76,7 +124,11 @@ public DateTimeOffset? RefreshTokenExpiresIn
}
}
- ///
+ ///
+ /// The expiry date as calculated by the timestamp of when the result was created plus
+ /// the value in seconds for the `expires_in` key.
+ ///
+ /// Timestamp of the creation of the object instance plus the expires_in seconds parsed from the callback URI.
public DateTimeOffset? ExpiresIn
{
get
diff --git a/src/Essentials/src/nugetreadme.txt b/src/Essentials/src/nugetreadme.txt
deleted file mode 100644
index a30936bd6051..000000000000
--- a/src/Essentials/src/nugetreadme.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-## Microsoft.Maui.Essentials
-
-Thank you for installing Microsoft.Maui.Essentials, be sure to read through our full documentation at:
-https://aka.ms/xamarinessentials
-
-## Setup
-
-Ensure that you install Microsoft.Maui.Essentials into all of your projects.
-
-For Android projects there is a small amount of setup needed to handle permissions. Please follow our short guide at:
-https://aka.ms/essentials-getstarted
-
-## Release Notes
-
-See our full release notes for more information: https://aka.ms/essentials-releasenotes
diff --git a/src/Essentials/test/DeviceTests/Directory.Build.targets b/src/Essentials/test/DeviceTests/Directory.Build.targets
index e170c0e72789..ee0f29e9005c 100644
--- a/src/Essentials/test/DeviceTests/Directory.Build.targets
+++ b/src/Essentials/test/DeviceTests/Directory.Build.targets
@@ -1,7 +1,7 @@
-
+
\ No newline at end of file
diff --git a/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj b/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj
index b9ece6c582ea..a43927241f0b 100644
--- a/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj
+++ b/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj
@@ -6,6 +6,8 @@
true
Microsoft.Maui.Essentials.DeviceTests
Microsoft.Maui.Essentials.DeviceTests
+
+ maccatalyst-x64
diff --git a/src/Essentials/test/DeviceTests/Tests/WebAuthenticator_Tests.cs b/src/Essentials/test/DeviceTests/Tests/WebAuthenticator_Tests.cs
index 783952e49c65..b1a692aa1899 100644
--- a/src/Essentials/test/DeviceTests/Tests/WebAuthenticator_Tests.cs
+++ b/src/Essentials/test/DeviceTests/Tests/WebAuthenticator_Tests.cs
@@ -31,6 +31,31 @@ public async Task Redirect(string urlBase, string callbackScheme, string accessT
Assert.True(r?.ExpiresIn > DateTime.UtcNow);
}
+ [Theory]
+ [InlineData(
+ "https://xamarin-essentials-auth-sample.azurewebsites.net/redirect",
+ "xamarinessentials",
+ "testtokenvalue",
+ "testrefreshvalue",
+ 99)]
+ [Trait(Traits.InteractionType, Traits.InteractionTypes.Human)]
+ public async Task RedirectWithResponseDecoder(string urlBase, string callbackScheme, string accessToken, string refreshToken, int expires)
+ {
+ var responseDecoder = new TestResponseDecoder();
+ var r = await WebAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions
+ {
+ Url = new Uri($"{urlBase}?access_token={accessToken}&refresh_token={refreshToken}&expires={expires}"),
+ CallbackUrl = new Uri($"{callbackScheme}://"),
+ ResponseDecoder = responseDecoder
+ });
+
+ Assert.Equal(accessToken, r?.AccessToken);
+ Assert.Equal(refreshToken, r?.RefreshToken);
+ Assert.NotNull(r?.ExpiresIn);
+ Assert.True(r?.ExpiresIn > DateTime.UtcNow);
+ Assert.Equal(1, responseDecoder.CallCount);
+ }
+
[Theory]
[InlineData("xamarinessentials://#access_token=blah&refresh_token=blah2&expires=1", "blah", "blah2", "1")]
[InlineData("xamarinessentials://?access_token=blah&refresh_token=blah2&expires=1", "blah", "blah2", "1")]
@@ -43,5 +68,16 @@ public void ParseQueryString(string url, string accessToken, string refreshToken
Assert.Equal(refreshToken, r?["refresh_token"]);
Assert.Equal(expires, r?["expires"]);
}
+
+ internal class TestResponseDecoder : IWebAuthenticatorResponseDecoder
+ {
+ internal int CallCount = 0;
+
+ public IDictionary DecodeResponse(Uri uri)
+ {
+ CallCount++;
+ return WebUtils.ParseQueryString(uri.ToString());
+ }
+ }
}
}
diff --git a/src/Graphics/src/Graphics.Skia/Graphics.Skia.csproj b/src/Graphics/src/Graphics.Skia/Graphics.Skia.csproj
index 6e4396644de8..c47bc2af58d8 100644
--- a/src/Graphics/src/Graphics.Skia/Graphics.Skia.csproj
+++ b/src/Graphics/src/Graphics.Skia/Graphics.Skia.csproj
@@ -23,9 +23,9 @@
-
+
-
+
diff --git a/src/Graphics/src/Graphics.Skia/SkiaImage.cs b/src/Graphics/src/Graphics.Skia/SkiaImage.cs
index f85e5d05c4c9..84b96a4154eb 100644
--- a/src/Graphics/src/Graphics.Skia/SkiaImage.cs
+++ b/src/Graphics/src/Graphics.Skia/SkiaImage.cs
@@ -119,6 +119,9 @@ public async Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png,
private Stream GetSkStream(ImageFormat format, float quality)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
// Skia quality range from 0-100, this is supported by jpeg and webp. Higher values correspond to improved visual quality, but less compression.
const int MaxSKQuality = 100;
var skQuality = (int)(MaxSKQuality * quality);
diff --git a/src/Graphics/src/Graphics.Win2D/Graphics.Win2D.csproj b/src/Graphics/src/Graphics.Win2D/Graphics.Win2D.csproj
index e129ccafd1e2..078150692e62 100644
--- a/src/Graphics/src/Graphics.Win2D/Graphics.Win2D.csproj
+++ b/src/Graphics/src/Graphics.Win2D/Graphics.Win2D.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/src/Graphics/src/Graphics.Win2D/W2DImage.cs b/src/Graphics/src/Graphics.Win2D/W2DImage.cs
index 16b1e542ff4d..886cfde46e4c 100644
--- a/src/Graphics/src/Graphics.Win2D/W2DImage.cs
+++ b/src/Graphics/src/Graphics.Win2D/W2DImage.cs
@@ -72,6 +72,9 @@ public IImage Resize(float width, float height, ResizeMode resizeMode = ResizeMo
public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
switch (format)
{
case ImageFormat.Jpeg:
@@ -85,6 +88,9 @@ public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float qual
public async Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
switch (format)
{
case ImageFormat.Jpeg:
diff --git a/src/Graphics/src/Graphics/Font.cs b/src/Graphics/src/Graphics/Font.cs
index 27e375c7c92a..9a31558bf6a0 100644
--- a/src/Graphics/src/Graphics/Font.cs
+++ b/src/Graphics/src/Graphics/Font.cs
@@ -55,5 +55,9 @@ public override int GetHashCode()
public bool IsDefault
=> string.IsNullOrEmpty(Name);
+
+ public static bool operator ==(Font left, Font right) => left.Equals(right);
+
+ public static bool operator !=(Font left, Font right) => !(left == right);
}
}
diff --git a/src/Graphics/src/Graphics/FontSource.cs b/src/Graphics/src/Graphics/FontSource.cs
index a7127e2d044a..912d25484394 100644
--- a/src/Graphics/src/Graphics/FontSource.cs
+++ b/src/Graphics/src/Graphics/FontSource.cs
@@ -23,5 +23,11 @@ public bool Equals(FontSource other)
public override int GetHashCode()
=> Name.GetHashCode() ^ Weight.GetHashCode() ^ FontStyleType.GetHashCode();
+
+ public override bool Equals(object? obj) => obj is FontSource other && Equals(other);
+
+ public static bool operator ==(FontSource left, FontSource right) => left.Equals(right);
+
+ public static bool operator !=(FontSource left, FontSource right) => !(left == right);
}
}
diff --git a/src/Graphics/src/Graphics/Graphics.csproj b/src/Graphics/src/Graphics/Graphics.csproj
index e3d3e8afd112..70f3e6376e51 100644
--- a/src/Graphics/src/Graphics/Graphics.csproj
+++ b/src/Graphics/src/Graphics/Graphics.csproj
@@ -16,14 +16,14 @@
$(NoWarn);CA1307;CA1309;CS1591;RS0026;RS0027;RS0041
-
+
-
+
diff --git a/src/Graphics/src/Graphics/PlatformImage.cs b/src/Graphics/src/Graphics/PlatformImage.cs
index 738c5e64509f..3449223fb6fc 100644
--- a/src/Graphics/src/Graphics/PlatformImage.cs
+++ b/src/Graphics/src/Graphics/PlatformImage.cs
@@ -46,6 +46,9 @@ public IImage Resize(float width, float height, ResizeMode resizeMode = ResizeMo
public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
if (format == _originalFormat)
{
stream.Write(_bytes, 0, _bytes.Length);
@@ -58,6 +61,9 @@ public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float qual
public Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
if (format == _originalFormat)
{
Save(stream, format, quality);
diff --git a/src/Graphics/src/Graphics/Platforms/Android/AndroidDrawingImplicitConversions.cs b/src/Graphics/src/Graphics/Platforms/Android/AndroidDrawingImplicitConversions.cs
index 715752b40aac..0b96eb410a90 100644
--- a/src/Graphics/src/Graphics/Platforms/Android/AndroidDrawingImplicitConversions.cs
+++ b/src/Graphics/src/Graphics/Platforms/Android/AndroidDrawingImplicitConversions.cs
@@ -1,18 +1,15 @@
-using System;
-using Android.Graphics;
-
namespace Microsoft.Maui.Graphics
{
public partial struct RectF
{
- public static implicit operator global::Android.Graphics.Rect(RectF rect) => new global::Android.Graphics.Rect((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
- public static implicit operator global::Android.Graphics.RectF(RectF rect) => new global::Android.Graphics.RectF(rect.X, rect.Y, rect.Width, rect.Height);
+ public static implicit operator global::Android.Graphics.Rect(RectF rect) => new global::Android.Graphics.Rect((int)rect.X, (int)rect.Y, (int)(rect.X + rect.Width), (int)(rect.Y + rect.Height));
+ public static implicit operator global::Android.Graphics.RectF(RectF rect) => new global::Android.Graphics.RectF(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
}
public partial struct Rect
{
- public static implicit operator global::Android.Graphics.Rect(Rect rect) => new global::Android.Graphics.Rect((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height);
- public static implicit operator global::Android.Graphics.RectF(Rect rect) => new global::Android.Graphics.RectF((float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height);
+ public static implicit operator global::Android.Graphics.Rect(Rect rect) => new global::Android.Graphics.Rect((int)rect.X, (int)rect.Y, (int)(rect.X + rect.Width), (int)(rect.Y + rect.Height));
+ public static implicit operator global::Android.Graphics.RectF(Rect rect) => new global::Android.Graphics.RectF((float)rect.X, (float)rect.Y, (float)(rect.X + rect.Width), (float)(rect.Y + rect.Height));
}
public partial struct PointF
@@ -26,4 +23,4 @@ public partial struct Point
public static implicit operator global::Android.Graphics.PointF(Point size) => new global::Android.Graphics.PointF((float)size.X, (float)size.Y);
public static implicit operator global::Android.Graphics.Point(Point size) => new global::Android.Graphics.Point((int)size.X, (int)size.Y);
}
-}
+}
\ No newline at end of file
diff --git a/src/Graphics/src/Graphics/Platforms/Android/PlatformImage.cs b/src/Graphics/src/Graphics/Platforms/Android/PlatformImage.cs
index 3126566d5b67..2a36cdb28955 100644
--- a/src/Graphics/src/Graphics/Platforms/Android/PlatformImage.cs
+++ b/src/Graphics/src/Graphics/Platforms/Android/PlatformImage.cs
@@ -91,6 +91,9 @@ public IImage Resize(float width, float height, ResizeMode resizeMode = ResizeMo
public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
switch (format)
{
case ImageFormat.Jpeg:
@@ -104,6 +107,9 @@ public void Save(Stream stream, ImageFormat format = ImageFormat.Png, float qual
public async Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
switch (format)
{
case ImageFormat.Jpeg:
diff --git a/src/Graphics/src/Graphics/Platforms/Mac/PlatformImage.cs b/src/Graphics/src/Graphics/Platforms/Mac/PlatformImage.cs
index 15ba4467544a..d48f98cf4157 100644
--- a/src/Graphics/src/Graphics/Platforms/Mac/PlatformImage.cs
+++ b/src/Graphics/src/Graphics/Platforms/Mac/PlatformImage.cs
@@ -37,6 +37,9 @@ public async Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png,
private NSData CreateRepresentation(ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
var previous = NSApplication.CheckForIllegalCrossThreadCalls;
NSApplication.CheckForIllegalCrossThreadCalls = false;
diff --git a/src/Graphics/src/Graphics/Platforms/iOS/PlatformImage.cs b/src/Graphics/src/Graphics/Platforms/iOS/PlatformImage.cs
index 2929249363d3..c1ad1b4c64fa 100644
--- a/src/Graphics/src/Graphics/Platforms/iOS/PlatformImage.cs
+++ b/src/Graphics/src/Graphics/Platforms/iOS/PlatformImage.cs
@@ -104,6 +104,9 @@ public async Task SaveAsync(Stream stream, ImageFormat format = ImageFormat.Png,
private NSData CreateData(ImageFormat format = ImageFormat.Png, float quality = 1)
{
+ if (quality < 0 || quality > 1)
+ throw new ArgumentOutOfRangeException(nameof(quality), "quality must be in the range of 0..1");
+
NSData data;
switch (format)
{
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt
index d7ee0ca3d13c..a36f2dd26086 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-android/PublicAPI.Unshipped.txt
@@ -763,6 +763,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -819,6 +820,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt
index 0463e087ec0c..b0da109bd6bf 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-ios/PublicAPI.Unshipped.txt
@@ -767,6 +767,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -823,6 +824,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
index 0463e087ec0c..b0da109bd6bf 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
@@ -767,6 +767,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -823,6 +824,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt
index eec3fedad594..0c6e1b80c93a 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-macos/PublicAPI.Unshipped.txt
@@ -767,6 +767,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -823,6 +824,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
index 915b0298a283..3f8260e664ad 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-tizen/PublicAPI.Unshipped.txt
@@ -725,6 +725,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -750,6 +751,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt
index 9136ed03ed57..92b69f39ee7f 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net-windows/PublicAPI.Unshipped.txt
@@ -721,6 +721,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -746,6 +747,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt
index 915b0298a283..3f8260e664ad 100644
--- a/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/net/PublicAPI.Unshipped.txt
@@ -725,6 +725,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -750,6 +751,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt b/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt
index 915b0298a283..3f8260e664ad 100644
--- a/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt
+++ b/src/Graphics/src/Graphics/PublicAPI/netstandard/PublicAPI.Unshipped.txt
@@ -725,6 +725,7 @@ Microsoft.Maui.Graphics.WindingMode.NonZero = 0 -> Microsoft.Maui.Graphics.Windi
Microsoft.Maui.Graphics.XmlnsPrefixAttribute
override Microsoft.Maui.Graphics.Color.GetHashCode() -> int
override Microsoft.Maui.Graphics.Font.GetHashCode() -> int
+override Microsoft.Maui.Graphics.FontSource.Equals(object? obj) -> bool
override Microsoft.Maui.Graphics.FontSource.GetHashCode() -> int
override Microsoft.Maui.Graphics.GradientPaint.IsTransparent.get -> bool
override Microsoft.Maui.Graphics.ImagePaint.IsTransparent.get -> bool
@@ -750,6 +751,10 @@ readonly Microsoft.Maui.Graphics.FontSource.Weight -> int
static Microsoft.Maui.Graphics.CanvasState.GetLengthScale(System.Numerics.Matrix3x2 matrix) -> float
static Microsoft.Maui.Graphics.Font.Default.get -> Microsoft.Maui.Graphics.Font
static Microsoft.Maui.Graphics.Font.DefaultBold.get -> Microsoft.Maui.Graphics.Font
+static Microsoft.Maui.Graphics.Font.operator !=(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.Font.operator ==(Microsoft.Maui.Graphics.Font left, Microsoft.Maui.Graphics.Font right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator !=(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
+static Microsoft.Maui.Graphics.FontSource.operator ==(Microsoft.Maui.Graphics.FontSource left, Microsoft.Maui.Graphics.FontSource right) -> bool
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(double angle) -> double
static Microsoft.Maui.Graphics.GeometryUtil.DegreesToRadians(float angle) -> float
static Microsoft.Maui.Graphics.GeometryUtil.EllipseAngleToPoint(float x, float y, float width, float height, float angleInDegrees) -> Microsoft.Maui.Graphics.PointF
diff --git a/src/Graphics/src/Text.Markdig/Graphics.Text.Markdig.csproj b/src/Graphics/src/Text.Markdig/Graphics.Text.Markdig.csproj
index a05eea33a890..fe92927c5650 100644
--- a/src/Graphics/src/Text.Markdig/Graphics.Text.Markdig.csproj
+++ b/src/Graphics/src/Text.Markdig/Graphics.Text.Markdig.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/src/Graphics/tests/DeviceTests/Directory.Build.targets b/src/Graphics/tests/DeviceTests/Directory.Build.targets
index e170c0e72789..ee0f29e9005c 100644
--- a/src/Graphics/tests/DeviceTests/Directory.Build.targets
+++ b/src/Graphics/tests/DeviceTests/Directory.Build.targets
@@ -1,7 +1,7 @@
-
+
\ No newline at end of file
diff --git a/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj b/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj
index 3038be2718ee..52b3534462b4 100644
--- a/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj
+++ b/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj
@@ -6,6 +6,8 @@
true
Microsoft.Maui.Graphics.DeviceTests
Microsoft.Maui.Graphics.DeviceTests
+
+ maccatalyst-x64
diff --git a/src/Graphics/tests/DeviceTests/Tests/ImageTests.cs b/src/Graphics/tests/DeviceTests/Tests/ImageTests.cs
new file mode 100644
index 000000000000..9f5c318de21f
--- /dev/null
+++ b/src/Graphics/tests/DeviceTests/Tests/ImageTests.cs
@@ -0,0 +1,107 @@
+using System.Threading.Tasks;
+using Microsoft.Maui.Storage;
+using Xunit;
+using System;
+
+#if WINDOWS
+using Microsoft.Maui.Graphics.Win2D;
+using PlatformImageLoadingService = Microsoft.Maui.Graphics.Win2D.W2DImageLoadingService;
+#else
+using Microsoft.Maui.Graphics.Platform;
+#endif
+
+namespace Microsoft.Maui.Graphics.DeviceTests;
+
+public class ImageTests
+{
+ [Theory]
+ [InlineData(ImageFormat.Png, 1.0f)]
+ [InlineData(ImageFormat.Png, 0.8f)]
+ [InlineData(ImageFormat.Png, 0.4f)]
+ [InlineData(ImageFormat.Jpeg, 1.0f)]
+ [InlineData(ImageFormat.Jpeg, 0.8f)]
+ [InlineData(ImageFormat.Jpeg, 0.4f)]
+ public async Task CanGetBytesFromImage(ImageFormat format, float quality)
+ {
+ var service = new PlatformImageLoadingService();
+
+ using var stream = await FileSystem.OpenAppPackageFileAsync("dotnet_bot.png");
+ using var image = service.FromStream(stream);
+
+ var bytes = image.AsBytes(format, quality);
+
+ Assert.NotNull(bytes);
+ Assert.NotEmpty(bytes);
+ }
+
+ [Theory]
+ [InlineData(ImageFormat.Png, 1.0f)]
+ [InlineData(ImageFormat.Png, 0.8f)]
+ [InlineData(ImageFormat.Png, 0.4f)]
+ [InlineData(ImageFormat.Jpeg, 1.0f)]
+ [InlineData(ImageFormat.Jpeg, 0.8f)]
+ [InlineData(ImageFormat.Jpeg, 0.4f)]
+ public async Task CanGetStreamFromImage(ImageFormat format, float quality)
+ {
+ var service = new PlatformImageLoadingService();
+
+ using var stream = await FileSystem.OpenAppPackageFileAsync("dotnet_bot.png");
+ using var image = service.FromStream(stream);
+
+ var newStream = image.AsStream(format, quality);
+
+ Assert.NotNull(newStream);
+ Assert.True(newStream.Length > 0, "Assert.True(newStream.Length > 0)");
+ }
+
+ [Theory]
+ [InlineData(ImageFormat.Png, 2.0f)]
+ [InlineData(ImageFormat.Png, 80f)]
+ [InlineData(ImageFormat.Png, -0.8f)]
+ [InlineData(ImageFormat.Jpeg, 2.0f)]
+ [InlineData(ImageFormat.Jpeg, 80f)]
+ [InlineData(ImageFormat.Jpeg, -0.8f)]
+ public async Task AsBytesWithQualityOutOfRangeThrowsArgumentException(ImageFormat format, float quality)
+ {
+ var service = new PlatformImageLoadingService();
+
+ using var stream = await FileSystem.OpenAppPackageFileAsync("dotnet_bot.png");
+ using var image = service.FromStream(stream);
+
+ Assert.Throws(() => image.AsBytes(format, quality));
+ }
+
+ [Theory]
+ [InlineData(ImageFormat.Png, 2.0f)]
+ [InlineData(ImageFormat.Png, 80f)]
+ [InlineData(ImageFormat.Png, -0.8f)]
+ [InlineData(ImageFormat.Jpeg, 2.0f)]
+ [InlineData(ImageFormat.Jpeg, 80f)]
+ [InlineData(ImageFormat.Jpeg, -0.8f)]
+ public async Task AsBytesAsyncWithQualityOutOfRangeThrowsArgumentException(ImageFormat format, float quality)
+ {
+ var service = new PlatformImageLoadingService();
+
+ using var stream = await FileSystem.OpenAppPackageFileAsync("dotnet_bot.png");
+ using var image = service.FromStream(stream);
+
+ await Assert.ThrowsAsync(() => image.AsBytesAsync(format, quality));
+ }
+
+ [Theory]
+ [InlineData(ImageFormat.Png, 2.0f)]
+ [InlineData(ImageFormat.Png, 80f)]
+ [InlineData(ImageFormat.Png, -0.8f)]
+ [InlineData(ImageFormat.Jpeg, 2.0f)]
+ [InlineData(ImageFormat.Jpeg, 80f)]
+ [InlineData(ImageFormat.Jpeg, -0.8f)]
+ public async Task AsStreamWithQualityOutOfRangeThrowsArgumentException(ImageFormat format, float quality)
+ {
+ var service = new PlatformImageLoadingService();
+
+ using var stream = await FileSystem.OpenAppPackageFileAsync("dotnet_bot.png");
+ using var image = service.FromStream(stream);
+
+ Assert.Throws(() => image.AsStream(format, quality));
+ }
+}
diff --git a/src/Graphics/tests/Graphics.Tests/Graphics.Tests.csproj b/src/Graphics/tests/Graphics.Tests/Graphics.Tests.csproj
index 3af73cb53368..5c3fa99c2793 100644
--- a/src/Graphics/tests/Graphics.Tests/Graphics.Tests.csproj
+++ b/src/Graphics/tests/Graphics.Tests/Graphics.Tests.csproj
@@ -16,7 +16,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/src/Maui.InTree.props b/src/Maui.InTree.props
index 871983d2c833..0d44d03d3844 100644
--- a/src/Maui.InTree.props
+++ b/src/Maui.InTree.props
@@ -1,5 +1,26 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Maui.InTree.targets b/src/Maui.InTree.targets
index 2cbac3e108c0..acb0b2a424ca 100644
--- a/src/Maui.InTree.targets
+++ b/src/Maui.InTree.targets
@@ -1,12 +1,33 @@
+
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.nuspec/Microsoft.Maui.Controls.Debug.targets b/src/Microsoft.Maui.Controls.Debug.targets
similarity index 85%
rename from .nuspec/Microsoft.Maui.Controls.Debug.targets
rename to src/Microsoft.Maui.Controls.Debug.targets
index afa07be9def5..e33ffcee55d1 100644
--- a/.nuspec/Microsoft.Maui.Controls.Debug.targets
+++ b/src/Microsoft.Maui.Controls.Debug.targets
@@ -1,11 +1,10 @@
+
True
<_MauiForceXamlCForDebug>True
-
-
@@ -27,4 +26,5 @@
DebugSymbols = "$(DebugSymbols)"
DebugType = "$(DebugType)"/>
+
\ No newline at end of file
diff --git a/.nuspec/Microsoft.Maui.TestUtils.DeviceTests.Runners.targets b/src/Microsoft.Maui.TestUtils.DeviceTests.Runners.targets
similarity index 100%
rename from .nuspec/Microsoft.Maui.TestUtils.DeviceTests.Runners.targets
rename to src/Microsoft.Maui.TestUtils.DeviceTests.Runners.targets
diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/src/MultiTargeting.targets
similarity index 100%
rename from .nuspec/Microsoft.Maui.Controls.MultiTargeting.targets
rename to src/MultiTargeting.targets
diff --git a/src/ProfiledAot/src/Directory.Build.targets b/src/ProfiledAot/src/Directory.Build.targets
index 69cd68b52df7..660fb6c50606 100644
--- a/src/ProfiledAot/src/Directory.Build.targets
+++ b/src/ProfiledAot/src/Directory.Build.targets
@@ -21,7 +21,7 @@
-
+
@@ -47,10 +47,10 @@
-
+
-
+
diff --git a/src/SingleProject/Resizetizer/src/AndroidAdaptiveIconGenerator.cs b/src/SingleProject/Resizetizer/src/AndroidAdaptiveIconGenerator.cs
index 1d639d995432..67f5571a4cf1 100644
--- a/src/SingleProject/Resizetizer/src/AndroidAdaptiveIconGenerator.cs
+++ b/src/SingleProject/Resizetizer/src/AndroidAdaptiveIconGenerator.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -27,6 +28,7 @@ public AndroidAdaptiveIconGenerator(ResizeImageInfo info, string appIconName, st
+
";
public IEnumerable Generate()
@@ -51,7 +53,7 @@ public IEnumerable Generate()
void ProcessBackground(List results, DirectoryInfo fullIntermediateOutputPath)
{
var backgroundFile = Info.Filename;
- var backgroundExists = File.Exists(backgroundFile);
+ var (backgroundExists, backgroundModified) = Utils.FileExists(backgroundFile);
var backgroundDestFilename = AppIconName + "_background.png";
if (backgroundExists)
@@ -63,8 +65,16 @@ void ProcessBackground(List results, DirectoryInfo fullInterme
{
var dir = Path.Combine(fullIntermediateOutputPath.FullName, dpi.Path);
var destination = Path.Combine(dir, backgroundDestFilename);
+ var (destinationExists, destinationModified) = Utils.FileExists(destination);
Directory.CreateDirectory(dir);
+ if (destinationModified > backgroundModified)
+ {
+ Logger.Log($"Skipping `{backgroundFile}` => `{destination}` file is up to date.");
+ results.Add(new ResizedImageInfo { Dpi = dpi, Filename = destination });
+ continue;
+ }
+
Logger.Log($"App Icon Background Part: " + destination);
if (backgroundExists)
@@ -87,7 +97,7 @@ void ProcessBackground(List results, DirectoryInfo fullInterme
void ProcessForeground(List results, DirectoryInfo fullIntermediateOutputPath)
{
var foregroundFile = Info.ForegroundFilename;
- var foregroundExists = File.Exists(foregroundFile);
+ var (foregroundExists, foregroundModified) = Utils.FileExists(foregroundFile);
var foregroundDestFilename = AppIconName + "_foreground.png";
if (foregroundExists)
@@ -99,8 +109,16 @@ void ProcessForeground(List results, DirectoryInfo fullInterme
{
var dir = Path.Combine(fullIntermediateOutputPath.FullName, dpi.Path);
var destination = Path.Combine(dir, foregroundDestFilename);
+ var (destinationExists, destinationModified) = Utils.FileExists(destination);
Directory.CreateDirectory(dir);
+ if (destinationModified > foregroundModified)
+ {
+ Logger.Log($"Skipping `{foregroundFile}` => `{destination}` file is up to date.");
+ results.Add(new ResizedImageInfo { Dpi = dpi, Filename = destination });
+ continue;
+ }
+
Logger.Log($"App Icon Foreground Part: " + destination);
if (foregroundExists)
@@ -122,14 +140,21 @@ void ProcessForeground(List results, DirectoryInfo fullInterme
void ProcessAdaptiveIcon(List results, DirectoryInfo fullIntermediateOutputPath)
{
- var adaptiveIconXmlStr = AdaptiveIconDrawableXml
- .Replace("{name}", AppIconName);
-
var dir = Path.Combine(fullIntermediateOutputPath.FullName, "mipmap-anydpi-v26");
var adaptiveIconDestination = Path.Combine(dir, AppIconName + ".xml");
var adaptiveIconRoundDestination = Path.Combine(dir, AppIconName + "_round.xml");
Directory.CreateDirectory(dir);
+ if (File.Exists(adaptiveIconDestination) && File.Exists(adaptiveIconRoundDestination))
+ {
+ results.Add(new ResizedImageInfo { Dpi = new DpiPath("mipmap-anydpi-v26", 1), Filename = adaptiveIconDestination });
+ results.Add(new ResizedImageInfo { Dpi = new DpiPath("mipmap-anydpi-v26", 1, "_round"), Filename = adaptiveIconRoundDestination });
+ return;
+ }
+
+ var adaptiveIconXmlStr = AdaptiveIconDrawableXml
+ .Replace("{name}", AppIconName);
+
// Write out the adaptive icon xml drawables
File.WriteAllText(adaptiveIconDestination, adaptiveIconXmlStr);
File.WriteAllText(adaptiveIconRoundDestination, adaptiveIconXmlStr);
diff --git a/src/SingleProject/Resizetizer/src/AppleIconAssetsGenerator.cs b/src/SingleProject/Resizetizer/src/AppleIconAssetsGenerator.cs
index f919382c34f8..1fa48ddc8fe1 100644
--- a/src/SingleProject/Resizetizer/src/AppleIconAssetsGenerator.cs
+++ b/src/SingleProject/Resizetizer/src/AppleIconAssetsGenerator.cs
@@ -41,6 +41,17 @@ public IEnumerable Generate()
var assetContentsFile = Path.Combine(outputAssetsDir, "Contents.json");
var appIconSetContentsFile = Path.Combine(outputAppIconSetDir, "Contents.json");
+ var (sourceExists, sourceModified) = Utils.FileExists(Info.Filename);
+ var (destinationExists, destinationModified) = Utils.FileExists(appIconSetContentsFile);
+
+ if (destinationModified > sourceModified)
+ {
+ Logger.Log($"Skipping `{Info.Filename}` => `{appIconSetContentsFile}` file is up to date.");
+ return new List {
+ new ResizedImageInfo { Dpi = new DpiPath("", 1), Filename = appIconSetContentsFile }
+ };
+ }
+
var infoJsonProp = new JsonObject
{
["info"] = new JsonObject
diff --git a/src/SingleProject/Resizetizer/src/ResizetizeImages.cs b/src/SingleProject/Resizetizer/src/ResizetizeImages.cs
index a6e4788eb8be..51670cbb0f98 100644
--- a/src/SingleProject/Resizetizer/src/ResizetizeImages.cs
+++ b/src/SingleProject/Resizetizer/src/ResizetizeImages.cs
@@ -170,9 +170,17 @@ void ProcessAppIcon(ResizeImageInfo img, ConcurrentBag resized
var destination = Resizer.GetRasterFileDestination(img, dpi, IntermediateOutputPath)
.Replace("{name}", appIconName);
+ var (sourceExists, sourceModified) = Utils.FileExists(img.Filename);
+ var (destinationExists, destinationModified) = Utils.FileExists(destination);
LogDebugMessage($"App Icon Destination: " + destination);
+ if (destinationModified > sourceModified)
+ {
+ Logger.Log($"Skipping `{img.Filename}` => `{destination}` file is up to date.");
+ continue;
+ }
+
appTool.Resize(dpi, destination);
}
}
diff --git a/src/SingleProject/Resizetizer/src/Resizetizer.csproj b/src/SingleProject/Resizetizer/src/Resizetizer.csproj
index 53b8a223d84d..8514096ef951 100644
--- a/src/SingleProject/Resizetizer/src/Resizetizer.csproj
+++ b/src/SingleProject/Resizetizer/src/Resizetizer.csproj
@@ -5,10 +5,13 @@
Microsoft.Maui.Resizetizer
Microsoft.Maui.Resizetizer
- Microsoft.Maui.Resizetizer.Sdk
+ Microsoft.Maui.Resizetizer
.NET MAUI SDK support for images, fonts, etc. Enabled via <UseMauiAssets>true</UseMauiAssets>.
- false
- <_SkiaPackagePath>build\
+ true
+
+ true
+
+ false
@@ -18,19 +21,22 @@
-
-
-
-
+
+
+
+
-
+
- <_CopyItems Include="$(TargetDir)**\*.dll" Exclude="$(TargetDir)System.*.dll" />
- <_CopyItems Include="$(TargetDir)**\*.so" />
- <_CopyItems Include="$(TargetDir)**\*.dylib" />
+ <_CopyItems Include="$(TargetDir)$(AssemblyName).dll" />
+ <_CopyItems Include="$(TargetDir)$(AssemblyName).pdb" />
+ <_CopyItems Include="nuget\buildTransitive\**" />
+ <_CopyItems Include="@(_ResizetizerFiles)" />
-
+
+
+
diff --git a/src/SingleProject/Resizetizer/src/ResizetizerPackages.projitems b/src/SingleProject/Resizetizer/src/ResizetizerPackages.projitems
index 8041459c8de8..defa7a62b762 100644
--- a/src/SingleProject/Resizetizer/src/ResizetizerPackages.projitems
+++ b/src/SingleProject/Resizetizer/src/ResizetizerPackages.projitems
@@ -2,6 +2,7 @@
+
@@ -18,14 +19,17 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -33,6 +37,7 @@
<_ResizetizerFiles Include="$(PkgSystem_Memory)\lib\netstandard2.0\System.Memory.dll" />
<_ResizetizerFiles Include="$(PkgSystem_Buffers)\lib\netstandard2.0\System.Buffers.dll" />
<_ResizetizerFiles Include="$(PkgSystem_Text_Json)\lib\netstandard2.0\System.Text.Json.dll" />
+ <_ResizetizerFiles Include="$(PkgSystem_Text_Encodings_Web)\lib\netstandard2.0\System.Text.Encodings.Web.dll" />
<_ResizetizerFiles Include="$(PkgMicrosoft_Bcl_AsyncInterfaces)\lib\netstandard2.0\Microsoft.Bcl.AsyncInterfaces.dll" />
<_ResizetizerFiles Include="$(PkgSystem_Numerics_Vectors)\lib\netstandard2.0\System.Numerics.Vectors.dll" />
<_ResizetizerFiles Include="$(PkgSystem_Runtime_CompilerServices_Unsafe)\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll" />
diff --git a/src/SingleProject/Resizetizer/src/Utils.cs b/src/SingleProject/Resizetizer/src/Utils.cs
index 115f7fdde517..0ae95d9d8c11 100644
--- a/src/SingleProject/Resizetizer/src/Utils.cs
+++ b/src/SingleProject/Resizetizer/src/Utils.cs
@@ -1,4 +1,5 @@
-using System.IO;
+using System;
+using System.IO;
using System.Text.RegularExpressions;
using SkiaSharp;
@@ -49,5 +50,12 @@ public static bool IsValidResourceFilename(string filename)
return null;
}
+
+ public static (bool Exists, DateTime Modified) FileExists(string path)
+ {
+ var exists = File.Exists(path);
+ var modified = exists ? File.GetLastWriteTimeUtc(path) : System.DateTime.MinValue;
+ return (exists, modified);
+ }
}
}
diff --git a/src/SingleProject/Resizetizer/src/WindowsIconGenerator.cs b/src/SingleProject/Resizetizer/src/WindowsIconGenerator.cs
index c051fb07ad27..907b235803d7 100644
--- a/src/SingleProject/Resizetizer/src/WindowsIconGenerator.cs
+++ b/src/SingleProject/Resizetizer/src/WindowsIconGenerator.cs
@@ -1,4 +1,5 @@
-using System.IO;
+using System;
+using System.IO;
using SkiaSharp;
namespace Microsoft.Maui.Resizetizer
@@ -27,11 +28,20 @@ public ResizedImageInfo Generate()
string destination = Path.Combine(destinationFolder, $"{fileName}.ico");
Directory.CreateDirectory(destinationFolder);
+ var (sourceExists, sourceModified) = Utils.FileExists(Info.Filename);
+ var (destinationExists, destinationModified) = Utils.FileExists(destination);
+
Logger.Log($"Generating ICO: {destination}");
var tools = new SkiaSharpAppIconTools(Info, Logger);
var dpi = new DpiPath(fileName, 1.0m, size: new SKSize(64, 64));
+ if (destinationModified > sourceModified)
+ {
+ Logger.Log($"Skipping `{Info.Filename}` => `{destination}` file is up to date.");
+ return new ResizedImageInfo { Dpi = dpi, Filename = destination };
+ }
+
MemoryStream memoryStream = new MemoryStream();
tools.Resize(dpi, destination, () => memoryStream);
memoryStream.Position = 0;
diff --git a/.nuspec/Microsoft.Maui.Resizetizer.targets b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
similarity index 98%
rename from .nuspec/Microsoft.Maui.Resizetizer.targets
rename to src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
index 8d91c3c91f99..e3f1972e7c44 100644
--- a/.nuspec/Microsoft.Maui.Resizetizer.targets
+++ b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
@@ -668,6 +668,24 @@
+
+
+
+
+
+
+ <_MauiAppxManifest Include="@(AppxManifest)" />
+
+
+
+
+
diff --git a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.props b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.props
new file mode 100644
index 000000000000..058246e40862
--- /dev/null
+++ b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.props
@@ -0,0 +1 @@
+
diff --git a/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.targets b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.targets
new file mode 100644
index 000000000000..a57ee33416b5
--- /dev/null
+++ b/src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.targets
@@ -0,0 +1,13 @@
+
+
+
+ true
+
+
+
+
+
+ $(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)Microsoft.Maui.Resizetizer.After.targets
+
+
+
\ No newline at end of file
diff --git a/src/SingleProject/Resizetizer/test/UnitTests/ResizetizeImagesTests.cs b/src/SingleProject/Resizetizer/test/UnitTests/ResizetizeImagesTests.cs
index 7dff630d8c33..8bfe2acecac8 100644
--- a/src/SingleProject/Resizetizer/test/UnitTests/ResizetizeImagesTests.cs
+++ b/src/SingleProject/Resizetizer/test/UnitTests/ResizetizeImagesTests.cs
@@ -1362,6 +1362,36 @@ public void ShouldResize(string filename, string baseSize, bool resize)
var size = ResizeImageInfo.Parse(item);
Assert.Equal(resize, size.Resize);
}
+
+ [Theory]
+ [InlineData("android")]
+ [InlineData("uwp")]
+ [InlineData("ios")]
+ public void GenerationSkippedOnIncrementalBuild(string platform)
+ {
+ var items = new[]
+ {
+ new TaskItem("images/dotnet_logo.svg", new Dictionary
+ {
+ ["IsAppIcon"] = bool.TrueString,
+ ["ForegroundFile"] = $"images/dotnet_foreground.svg",
+ ["Link"] = "appicon",
+ ["BackgroundFile"] = $"images/dotnet_background.svg",
+ }),
+ };
+
+ var task = GetNewTask(platform, items);
+ var success = task.Execute();
+ Assert.True(success, LogErrorEvents.FirstOrDefault()?.Message);
+
+ LogErrorEvents.Clear();
+ LogMessageEvents.Clear();
+ task = GetNewTask(platform, items);
+ success = task.Execute();
+ Assert.True(success, LogErrorEvents.FirstOrDefault()?.Message);
+
+ Assert.True(LogMessageEvents.Any(x => x.Message.Contains("Skipping ", StringComparison.OrdinalIgnoreCase)), $"Image generation should have been skipped.");
+ }
}
}
}
diff --git a/src/SingleProject/Resizetizer/test/UnitTests/Resizetizer.UnitTests.csproj b/src/SingleProject/Resizetizer/test/UnitTests/Resizetizer.UnitTests.csproj
index a17f15122fad..091add07d083 100644
--- a/src/SingleProject/Resizetizer/test/UnitTests/Resizetizer.UnitTests.csproj
+++ b/src/SingleProject/Resizetizer/test/UnitTests/Resizetizer.UnitTests.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml b/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml
index a7e10988fd90..2707ecb83804 100644
--- a/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml
+++ b/src/Templates/src/templates/maui-mobile/Resources/Styles/Styles.xaml
@@ -20,7 +20,7 @@