diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..7317893
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,199 @@
+###############################
+# Core EditorConfig Options #
+###############################
+
+root = true
+
+# All files
+[*]
+charset = utf-8
+trim_trailing_whitespace = true
+
+# MSBuild
+[*.{csproj,proj,projitems,shproj,fsproj,targets,props}]
+indent_style = space
+indent_size = 2
+
+# XML config files
+[*.{xml,axml,xaml,config,nuspec,resx}]
+indent_style = space
+indent_size = 2
+
+# JSON files
+[*.json]
+indent_style = space
+indent_size = 2
+
+# F# files
+[*.{fs, fsx, fsi}]
+indent_style = space
+indent_size = 4
+
+# Code files
+[*.{cs,csx,vb,vbx}]
+insert_final_newline = true
+indent_style = tab
+tab_width = 8
+indent_size = 8
+max_line_length = 180
+
+###############################
+# .NET Coding Conventions #
+###############################
+
+[*.{cs,vb}]
+# Organize usings
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+
+# Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_event = false:suggestion
+
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+
+# Avoid redundant accessibility modifiers when they're default
+dotnet_style_require_accessibility_modifiers = omit_if_default:suggestion
+dotnet_style_readonly_field = true:suggestion
+
+# Expression-level preferences
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+
+###############################
+# Naming Conventions #
+###############################
+
+# Style Definitions
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+dotnet_naming_style.underline_separator.word_separator = _
+dotnet_naming_style.underline_separator.capitalization = all_lower
+
+# Symbol Definitions
+dotnet_naming_symbols.parameters.applicable_kinds = parameter
+dotnet_naming_symbols.parameters.applicable_accessibilities = *
+
+dotnet_naming_symbols.fields.applicable_kinds = field
+
+dotnet_naming_symbols.constant_fields.applicable_kinds = field
+dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
+dotnet_naming_symbols.constant_fields.required_modifiers = const
+
+# Use CamelCase for parameters
+dotnet_naming_rule.method_parameters_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.method_parameters_should_be_camel_case.symbols = parameters
+dotnet_naming_rule.method_parameters_should_be_camel_case.style = camel_case
+
+# Use PascalCase for constant fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
+dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
+
+# Use underline separator for instance fields
+dotnet_naming_rule.fields_should_be_underline_separator.severity = suggestion
+dotnet_naming_rule.fields_should_be_underline_separator.symbols = fields
+dotnet_naming_rule.fields_should_be_underline_separator.style = underline_separator
+
+
+###############################
+# C# Code Style Rules #
+###############################
+
+[*.cs]
+# var preferences
+csharp_style_var_for_built_in_types = true:silent
+csharp_style_var_when_type_is_apparent = true:silent
+csharp_style_var_elsewhere = true:silent
+
+# Expression-bodied members
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+
+# Pattern-matching preferences
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+
+# Null-checking preferences
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Modifier preferences
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
+
+# Expression-level preferences
+csharp_prefer_braces = true:silent
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+
+###############################
+# C# Formatting Rules #
+###############################
+
+# Newline settings
+csharp_new_line_before_open_brace = methods,types
+csharp_new_line_before_else = false
+csharp_new_line_before_catch = false
+csharp_new_line_before_finally = false
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+
+# Indentation preferences
+csharp_indent_switch_labels = false
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+
+# Space preferences
+csharp_space_after_cast = true
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = true
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = true
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_before_open_square_brackets = true
+
+# Wrapping preferences
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
+
+##################################
+# Visual Basic Code Style Rules #
+##################################
+
+[*.vb]
+# Modifier preferences
+visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..0377b39
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,8 @@
+{
+ "recommendations": [
+ "ms-vscode.csharp",
+ "ms-vscode.mono-debug",
+ "wghats.vscode-nxunit-test-adapter",
+ "visualstudioexptteam.vscodeintellicode",
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..a0ddfb7
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,22 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch",
+ "type": "mono",
+ "request": "launch",
+ "program": "${workspaceRoot}/packages/NUnit.ConsoleRunner.3.9.0/tools/nunit3-console.exe ${workspaceRoot}/bin/TestDebug/generator-Tests.dll",
+ "cwd": "${workspaceRoot}bin/TestDebug/"
+ },
+ {
+ "name": "Attach",
+ "type": "mono",
+ "request": "attach",
+ "address": "localhost",
+ "port": 55555
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..bff3f6a
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "nxunitExplorer.nunit": "packages/NUnit.ConsoleRunner.3.9.0/tools/nunit3-console.exe",
+ "nxunitExplorer.modules": [
+ "bin/TestDebug/Xamarin.Android.Tools.AndroidSdk-Tests.dll"
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..87828d6
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,43 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "Build Xamarin.Android.Tools",
+ "type": "shell",
+ "command": "msbuild Xamarin.Android.Tools.sln /restore",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile"
+ ]
+ },
+ {
+ "label": "Clean Xamarin.Android.Tools",
+ "type": "shell",
+ "command": "msbuild Xamarin.Android.Tools.sln /restore /t:Clean",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile"
+ ]
+ },
+ {
+ "label": "Run Unit Tests",
+ "type": "shell",
+ "command": "make run-all-tests",
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "problemMatcher": [
+ "$msCompile"
+ ]
+ }
+ ]
+}
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..74fe6cf
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,25 @@
+
+
+
+
+ Debug
+
+
+ obj\
+
+
+ True
+
+
+ $(BaseIntermediateOutputPath)\$(Configuration)-$(TargetFramework.ToLowerInvariant())
+ $(MSBuildThisFileDirectory)bin\Build$(Configuration)\$(TargetFramework.ToLowerInvariant())\
+ $(MSBuildThisFileDirectory)bin\$(Configuration)\$(TargetFramework.ToLowerInvariant())\
+ $(MSBuildThisFileDirectory)bin\Test$(Configuration)-$(TargetFramework.ToLowerInvariant())\
+
+
+ $(BaseIntermediateOutputPath)\$(Configuration)
+ $(MSBuildThisFileDirectory)bin\Build$(Configuration)\
+ $(MSBuildThisFileDirectory)bin\$(Configuration)\
+ $(MSBuildThisFileDirectory)bin\Test$(Configuration)\
+
+
diff --git a/Makefile b/Makefile
index 6cf6e73..1c686c4 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ V ?= 0
include build-tools/scripts/msbuild.mk
all:
- $(MSBUILD) $(MSBUILD_FLAGS) Xamarin.Android.Tools.sln
+ $(MSBUILD) /restore $(MSBUILD_FLAGS) Xamarin.Android.Tools.sln
clean:
-$(MSBUILD) $(MSBUILD_FLAGS) /t:Clean Xamarin.Android.Tools.sln
diff --git a/NuGet.Config b/NuGet.Config
new file mode 100644
index 0000000..9eee256
--- /dev/null
+++ b/NuGet.Config
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/NuGet.config b/NuGet.config
index a877b8c..713d9fc 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -1,4 +1,8 @@
+
diff --git a/Xamarin.Android.Tools.code-workspace b/Xamarin.Android.Tools.code-workspace
new file mode 100644
index 0000000..be71cd0
--- /dev/null
+++ b/Xamarin.Android.Tools.code-workspace
@@ -0,0 +1,9 @@
+{
+ "folders": [
+ {
+ "path": "."
+ }
+ ],
+ "settings": {
+ }
+}
diff --git a/azure-pipelines.yaml b/azure-pipelines.yaml
index 1db8f6c..59a3e7b 100644
--- a/azure-pipelines.yaml
+++ b/azure-pipelines.yaml
@@ -1,14 +1,32 @@
name: Xamarin.Android.Tools $(Rev:r)
+trigger:
+ - master
+ - d16-*
+
+pr:
+ - master
+ - d16-*
+
+# Global variables
+variables:
+ DotNetCoreVersion: 3.1.100
+ HostedMac: Hosted Mac Internal
+ HostedWinVS2019: Hosted Windows 2019 with VS2019
+
jobs:
- job: windows
displayName: windows
- pool: Hosted VS2017
+ pool: $(HostedWinVS2019)
steps:
- - task: NuGetToolInstaller@1
+ - task: UseDotNet@2
+ displayName: Use .NET Core $(DotNetCoreVersion)
+ inputs:
+ version: $(DotNetCoreVersion)
+ - task: NuGetToolInstaller@0
displayName: 'Install NuGet'
inputs:
- versionSpec: '5.4.x'
+ versionSpec: 5.x
- task: NuGetCommand@2
displayName: 'NuGet Restore'
inputs:
@@ -38,25 +56,27 @@ jobs:
pathtoPublish: $(Build.ArtifactStagingDirectory)
- job: mac
displayName: mac
- pool: Hosted macOS
+ pool: $(HostedMac)
steps:
- - task: NuGetToolInstaller@1
- displayName: 'Install NuGet'
- inputs:
- versionSpec: '5.4.x'
- - task: NuGetCommand@2
- displayName: 'NuGet Restore'
+ - task: UseDotNet@2
+ displayName: Use .NET Core $(DotNetCoreVersion)
inputs:
- restoreSolution: Xamarin.Android.Tools.sln
- restoreDirectory: 'packages'
- - task: MSBuild@1
- displayName: 'Build solution Xamarin.Android.Tools.sln'
- inputs:
- solution: Xamarin.Android.Tools.sln
- - script: mono packages/nunit.consolerunner/3.9.0/tools/nunit3-console.exe bin/TestDebug/Xamarin.Android.Tools.AndroidSdk-Tests.dll
- displayName: Run Tests
+ version: $(DotNetCoreVersion)
+ - script: |
+ dotnet tool install --global boots
+ boots https://download.mono-project.com/archive/6.4.0/macos-10-universal/MonoFramework-MDK-6.4.0.198.macos10.xamarin.universal.pkg
+ displayName: Install Mono 6.4
+ - script: make prepare CONFIGURATION=$(Build.Configuration)
+ displayName: make prepare
+
+ - script: make all CONFIGURATION=$(Build.Configuration)
+ displayName: make all
+
+ - script: make run-all-tests CONFIGURATION=$(Build.Configuration)
+ displayName: make run-all-tests
+
- task: PublishTestResults@2
condition: always()
inputs:
testResultsFormat: NUnit
- testResultsFiles: TestResult.xml
+ testResultsFiles: TestResult*.xml
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs b/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs
index 2db516c..5a9e5a7 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/AndroidAppManifest.cs
@@ -130,42 +130,42 @@ public void WriteToFile (string fileName)
}
}
- static string NullIfEmpty (string value)
+ static string? NullIfEmpty (string? value)
{
return string.IsNullOrEmpty (value) ? null : value;
}
- public string PackageName {
+ public string? PackageName {
get { return (string) manifest.Attribute ("package"); }
set { manifest.SetAttributeValue ("package", NullIfEmpty (value)); }
}
- public string ApplicationLabel {
+ public string? ApplicationLabel {
get { return (string) application.Attribute (aNS + "label"); }
set { application.SetAttributeValue (aNS + "label", NullIfEmpty (value)); }
}
- public string ApplicationIcon {
+ public string? ApplicationIcon {
get { return (string) application.Attribute (aNS + "icon"); }
set { application.SetAttributeValue (aNS + "icon", NullIfEmpty (value)); }
}
- public string ApplicationTheme {
+ public string? ApplicationTheme {
get { return (string) application.Attribute (aNS + "theme"); }
set { application.SetAttributeValue (aNS + "theme", NullIfEmpty (value)); }
}
- public string VersionName {
+ public string? VersionName {
get { return (string) manifest.Attribute (aNS + "versionName"); }
set { manifest.SetAttributeValue (aNS + "versionName", NullIfEmpty (value)); }
}
- public string VersionCode {
+ public string? VersionCode {
get { return (string) manifest.Attribute (aNS + "versionCode"); }
set { manifest.SetAttributeValue (aNS + "versionCode", NullIfEmpty (value)); }
}
- public string InstallLocation {
+ public string? InstallLocation {
get { return (string) manifest.Attribute (aNS + "installLocation"); }
set { manifest.SetAttributeValue (aNS + "installLocation", NullIfEmpty (value)); }
}
@@ -190,7 +190,7 @@ public int? TargetSdkVersion {
int? apiLevel = versions.GetApiLevelFromId (version);
if (apiLevel.HasValue)
return apiLevel.Value;
- return versions.MaxStableVersion.ApiLevel;
+ return versions.MaxStableVersion?.ApiLevel;
}
return vn;
}
@@ -273,16 +273,16 @@ void RemoveAndroidPermissions (IEnumerable permissions)
}
[Obsolete ("Use GetLaunchableFastdevActivityName or GetLaunchableUserActivityName")]
- public string GetLaunchableActivityName ()
+ public string? GetLaunchableActivityName ()
{
return GetLaunchableFastDevActivityName ();
}
/// Gets an activity that can be used to initialize the override directory for fastdev.
[Obsolete ("This should not be needed anymore; Activity execution is not part of installation.")]
- public string GetLaunchableFastDevActivityName ()
+ public string? GetLaunchableFastDevActivityName ()
{
- string first = null;
+ string? first = null;
foreach (var a in GetLaunchableActivities ()) {
var name = (string) a.Attribute (aName);
//prefer the fastdev launcher, it's quicker
@@ -300,7 +300,7 @@ public string GetLaunchableFastDevActivityName ()
// We add a fake launchable activity for FastDev, but we don't want
// to launch that one when the user does Run or Debug
- public string GetLaunchableUserActivityName ()
+ public string? GetLaunchableUserActivityName ()
{
return GetLaunchableActivities ()
.Select (a => (string) a.Attribute (aName))
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs b/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs
index c12d7a4..1297e51 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/AndroidSdkInfo.cs
@@ -10,7 +10,7 @@ public class AndroidSdkInfo
{
AndroidSdkBase sdk;
- public AndroidSdkInfo (Action logger = null, string androidSdkPath = null, string androidNdkPath = null, string javaSdkPath = null)
+ public AndroidSdkInfo (Action? logger = null, string? androidSdkPath = null, string? androidNdkPath = null, string? javaSdkPath = null)
{
logger = logger ?? DefaultConsoleLogger;
@@ -71,10 +71,9 @@ orderby version descending
select p;
}
- static Version TryParseVersion (string v)
+ static Version? TryParseVersion (string v)
{
- Version version;
- if (Version.TryParse (v, out version))
+ if (Version.TryParse (v, out var version))
return version;
return null;
}
@@ -97,10 +96,13 @@ public string GetPlatformDirectoryFromId (string id)
return Path.Combine (AndroidSdkPath, "platforms", "android-" + id);
}
- public string TryGetPlatformDirectoryFromApiLevel (string idOrApiLevel, AndroidVersions versions)
+ public string? TryGetPlatformDirectoryFromApiLevel (string idOrApiLevel, AndroidVersions versions)
{
var id = versions.GetIdFromApiLevel (idOrApiLevel);
- var dir = GetPlatformDirectoryFromId (id);
+ if (id == null)
+ return null;
+
+ string? dir = GetPlatformDirectoryFromId (id);
if (Directory.Exists (dir))
return dir;
@@ -118,12 +120,12 @@ public bool IsPlatformInstalled (int apiLevel)
return apiLevel != 0 && Directory.Exists (GetPlatformDirectory (apiLevel));
}
- public string AndroidNdkPath {
+ public string? AndroidNdkPath {
get { return sdk.AndroidNdkPath; }
}
public string AndroidSdkPath {
- get { return sdk.AndroidSdkPath; }
+ get { return sdk.AndroidSdkPath!; }
}
public string [] AllAndroidSdkPaths {
@@ -133,14 +135,14 @@ public string [] AllAndroidSdkPaths {
}
public string JavaSdkPath {
- get { return sdk.JavaSdkPath; }
+ get { return sdk.JavaSdkPath!; }
}
public string AndroidNdkHostPlatform {
get { return sdk.NdkHostPlatform; }
}
- public static void SetPreferredAndroidNdkPath (string path, Action logger = null)
+ public static void SetPreferredAndroidNdkPath (string path, Action? logger = null)
{
logger = logger ?? DefaultConsoleLogger;
@@ -160,7 +162,7 @@ internal static void DefaultConsoleLogger (TraceLevel level, string message)
}
}
- public static void SetPreferredAndroidSdkPath (string path, Action logger = null)
+ public static void SetPreferredAndroidSdkPath (string path, Action? logger = null)
{
logger = logger ?? DefaultConsoleLogger;
@@ -168,7 +170,7 @@ public static void SetPreferredAndroidSdkPath (string path, Action logger = null)
+ public static void SetPreferredJavaSdkPath (string path, Action? logger = null)
{
logger = logger ?? DefaultConsoleLogger;
@@ -176,7 +178,7 @@ public static void SetPreferredJavaSdkPath (string path, Action logger = null)
+ public static void DetectAndSetPreferredJavaSdkPathToLatest (Action? logger = null)
{
if (OS.IsWindows)
throw new NotImplementedException ("Windows is not supported at this time.");
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersion.cs b/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersion.cs
index 9805fc6..5cb3a3b 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersion.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersion.cs
@@ -13,7 +13,7 @@ public class AndroidVersion
public string Id { get; private set; }
// Name of an Android release, e.g. "Oreo"
- public string CodeName { get; private set; }
+ public string? CodeName { get; private set; }
// Android version number, e.g. 8.0
public string OSVersion { get; private set; }
@@ -28,9 +28,9 @@ public class AndroidVersion
public bool Stable { get; private set; }
// Alternate Ids for a given API level. Allows for historical mapping, e.g. API-11 has alternate ID 'H'.
- internal string[] AlternateIds { get; set; }
+ internal string[]? AlternateIds { get; set; }
- public AndroidVersion (int apiLevel, string osVersion, string codeName = null, string id = null, bool stable = true)
+ public AndroidVersion (int apiLevel, string osVersion, string? codeName = null, string? id = null, bool stable = true)
{
if (osVersion == null)
throw new ArgumentNullException (nameof (osVersion));
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersions.cs b/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersions.cs
index a56dcf3..9896288 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersions.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/AndroidVersions.cs
@@ -13,8 +13,8 @@ public class AndroidVersions
List installedVersions = new List ();
public IReadOnlyList FrameworkDirectories { get; }
- public AndroidVersion MaxStableVersion { get; private set; }
- public AndroidVersion MinStableVersion { get; private set; }
+ public AndroidVersion? MaxStableVersion { get; private set; }
+ public AndroidVersion? MinStableVersion { get; private set; }
public IReadOnlyList InstalledBindingVersions { get; private set; }
@@ -33,7 +33,7 @@ public AndroidVersions (IEnumerable frameworkDirectories)
var dn = Path.GetFileName (dp);
// In "normal" use, `dp` will contain e.g. `...\MonoAndroid\v1.0`.
// We want the `MonoAndroid` dir, not the versioned dir.
- var p = dn.StartsWith ("v", StringComparison.Ordinal) ? Path.GetDirectoryName (dp) : dp;
+ var p = dn.StartsWith ("v", StringComparison.Ordinal) ? (Path.GetDirectoryName (dp) ?? "") : dp;
dirs.Add (Path.GetFullPath (p));
}
@@ -46,6 +46,8 @@ public AndroidVersions (IEnumerable frameworkDirectories)
.Select (file => AndroidVersion.Load (file));
LoadVersions (versions);
+
+ InstalledBindingVersions = new ReadOnlyCollection (installedVersions);
}
public AndroidVersions (IEnumerable versions)
@@ -56,6 +58,8 @@ public AndroidVersions (IEnumerable versions)
FrameworkDirectories = new ReadOnlyCollection (new string [0]);
LoadVersions (versions);
+
+ InstalledBindingVersions = new ReadOnlyCollection (installedVersions);
}
void LoadVersions (IEnumerable versions)
@@ -71,8 +75,6 @@ void LoadVersions (IEnumerable versions)
MinStableVersion = version;
}
}
-
- InstalledBindingVersions = new ReadOnlyCollection(installedVersions);
}
public int? GetApiLevelFromFrameworkVersion (string frameworkVersion)
@@ -100,7 +102,7 @@ static bool MatchesId (AndroidVersion version, string id)
(version.ApiLevel.ToString () == id);
}
- public string GetIdFromApiLevel (int apiLevel)
+ public string? GetIdFromApiLevel (int apiLevel)
{
return installedVersions.FirstOrDefault (v => v.ApiLevel == apiLevel)?.Id ??
KnownVersions.FirstOrDefault (v => v.ApiLevel == apiLevel)?.Id;
@@ -108,7 +110,7 @@ public string GetIdFromApiLevel (int apiLevel)
// Sometimes, e.g. when new API levels are introduced, the "API level" is a letter, not a number,
// e.g. 'API-H' for API-11, 'API-O' for API-26, etc.
- public string GetIdFromApiLevel (string apiLevel)
+ public string? GetIdFromApiLevel (string apiLevel)
{
if (int.TryParse (apiLevel, out var platform))
return GetIdFromApiLevel (platform);
@@ -116,19 +118,19 @@ public string GetIdFromApiLevel (string apiLevel)
KnownVersions.FirstOrDefault (v => MatchesId (v, apiLevel))?.Id;
}
- public string GetIdFromFrameworkVersion (string frameworkVersion)
+ public string? GetIdFromFrameworkVersion (string frameworkVersion)
{
return installedVersions.FirstOrDefault (v => MatchesFrameworkVersion (v, frameworkVersion))?.Id ??
KnownVersions.FirstOrDefault (v => MatchesFrameworkVersion (v, frameworkVersion))?.Id;
}
- public string GetFrameworkVersionFromApiLevel (int apiLevel)
+ public string? GetFrameworkVersionFromApiLevel (int apiLevel)
{
return installedVersions.FirstOrDefault (v => v.ApiLevel == apiLevel)?.FrameworkVersion ??
KnownVersions.FirstOrDefault (v => v.ApiLevel == apiLevel)?.FrameworkVersion;
}
- public string GetFrameworkVersionFromId (string id)
+ public string? GetFrameworkVersionFromId (string id)
{
return installedVersions.FirstOrDefault (v => MatchesId (v, id))?.FrameworkVersion ??
KnownVersions.FirstOrDefault (v => MatchesId (v, id))?.FrameworkVersion;
@@ -179,10 +181,10 @@ class EqualityComparer : IEqualityComparer
Func equals;
Func getHashCode;
- public EqualityComparer (Func equals, Func getHashCode = null)
+ public EqualityComparer (Func equals, Func? getHashCode = null)
{
this.equals = equals;
- this.getHashCode = getHashCode ?? (v => v.GetHashCode ());
+ this.getHashCode = getHashCode ?? (v => v?.GetHashCode () ?? 0);
}
public bool Equals (T x, T y)
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/FileUtil.cs b/src/Xamarin.Android.Tools.AndroidSdk/FileUtil.cs
index 6fe8487..1b84575 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/FileUtil.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/FileUtil.cs
@@ -16,7 +16,7 @@ public static void SystemRename (string sourceFile, string destFile)
{
//FIXME: use the atomic System.IO.File.Replace on NTFS
if (OS.IsWindows) {
- string wtmp = null;
+ string? wtmp = null;
if (File.Exists (destFile)) {
do {
wtmp = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/JdkInfo.cs b/src/Xamarin.Android.Tools.AndroidSdk/JdkInfo.cs
index 4d7f453..e82886d 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/JdkInfo.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/JdkInfo.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
@@ -20,7 +21,7 @@ public class JdkInfo {
public string HomePath {get;}
- public string Locator {get;}
+ public string? Locator {get;}
public string JarPath {get;}
public string JavaPath {get;}
@@ -28,10 +29,10 @@ public class JdkInfo {
public string JdkJvmPath {get;}
public ReadOnlyCollection IncludePath {get;}
- public Version Version => javaVersion.Value;
- public string Vendor {
+ public Version? Version => javaVersion.Value;
+ public string? Vendor {
get {
- if (GetJavaSettingsPropertyValue ("java.vendor", out string vendor))
+ if (GetJavaSettingsPropertyValue ("java.vendor", out string? vendor))
return vendor;
return null;
}
@@ -41,7 +42,7 @@ public string Vendor {
public IEnumerable JavaSettingsPropertyKeys => javaProperties.Value.Keys;
Lazy>> javaProperties;
- Lazy javaVersion;
+ Lazy javaVersion;
public JdkInfo (string homePath)
{
@@ -57,7 +58,7 @@ public JdkInfo (string homePath)
JavaPath = ProcessUtils.FindExecutablesInDirectory (binPath, "java").FirstOrDefault ();
JavacPath = ProcessUtils.FindExecutablesInDirectory (binPath, "javac").FirstOrDefault ();
- string topDir = null;
+ string? topDir = null;
foreach (string dir in JdkLibraryTopDirs) {
topDir = Path.Combine (HomePath, dir);
if (!Directory.Exists (topDir)) {
@@ -71,8 +72,8 @@ public JdkInfo (string homePath)
topDir = Path.Combine (HomePath, JdkLibraryTopDirs [0]);
JdkJvmPath = OS.IsMac
- ? FindLibrariesInDirectory (topDir, "jli").FirstOrDefault ()
- : FindLibrariesInDirectory (topDir, "jvm").FirstOrDefault ();
+ ? FindLibrariesInDirectory (topDir!, "jli").FirstOrDefault ()
+ : FindLibrariesInDirectory (topDir!, "jvm").FirstOrDefault ();
ValidateFile ("jar", JarPath);
ValidateFile ("java", JavaPath);
@@ -93,7 +94,7 @@ public JdkInfo (string homePath)
IncludePath = new ReadOnlyCollection (includes);
javaProperties = new Lazy>> (GetJavaProperties, LazyThreadSafetyMode.ExecutionAndPublication);
- javaVersion = new Lazy (GetJavaVersion, LazyThreadSafetyMode.ExecutionAndPublication);
+ javaVersion = new Lazy (GetJavaVersion, LazyThreadSafetyMode.ExecutionAndPublication);
}
public JdkInfo (string homePath, string locator)
@@ -107,7 +108,7 @@ public override string ToString()
return $"JdkInfo(Version={Version}, Vendor=\"{Vendor}\", HomePath=\"{HomePath}\", Locator=\"{Locator}\")";
}
- public bool GetJavaSettingsPropertyValues (string key, out IEnumerable value)
+ public bool GetJavaSettingsPropertyValues (string key, [NotNullWhen (true)] out IEnumerable? value)
{
value = null;
var props = javaProperties.Value;
@@ -118,7 +119,7 @@ public bool GetJavaSettingsPropertyValues (string key, out IEnumerable v
return false;
}
- public bool GetJavaSettingsPropertyValue (string key, out string value)
+ public bool GetJavaSettingsPropertyValue (string key, [NotNullWhen (true)] out string? value)
{
value = null;
var props = javaProperties.Value;
@@ -147,9 +148,9 @@ void ValidateFile (string name, string path)
static Regex NonDigitMatcher = new Regex (@"[^\d]", RegexOptions.Compiled | RegexOptions.CultureInvariant);
- Version GetJavaVersion ()
+ Version? GetJavaVersion ()
{
- string version = null;
+ string? version = null;
if (ReleaseProperties.TryGetValue ("JAVA_VERSION", out version) && !string.IsNullOrEmpty (version)) {
version = GetParsableVersion (version);
if (ReleaseProperties.TryGetValue ("BUILD_NUMBER", out var build) && !string.IsNullOrEmpty (build))
@@ -193,7 +194,7 @@ ReadOnlyDictionary GetReleaseProperties ()
return new ReadOnlyDictionary(props);
using (var release = File.OpenText (releasePath)) {
- string line;
+ string? line;
while ((line = release.ReadLine ()) != null) {
line = line.Trim ();
const string PropertyDelim = "=";
@@ -243,7 +244,7 @@ static Dictionary> GetJavaProperties (string java)
};
var props = new Dictionary> ();
- string curKey = null;
+ string? curKey = null;
if (!AnySystemJavasInstalled () && (java == "/usr/bin/java" || java == "java"))
return props;
@@ -266,8 +267,8 @@ static Dictionary> GetJavaProperties (string java)
return;
curKey = e.Data.Substring (NewValuePrefix.Length, delim - NewValuePrefix.Length);
var value = e.Data.Substring (delim + NameValueDelim.Length);
- List values;
- if (!props.TryGetValue (curKey, out values))
+ List? values;
+ if (!props.TryGetValue (curKey!, out values))
props.Add (curKey, values = new List ());
values.Add (value);
}
@@ -276,7 +277,7 @@ static Dictionary> GetJavaProperties (string java)
return props;
}
- public static IEnumerable GetKnownSystemJdkInfos (Action logger = null)
+ public static IEnumerable GetKnownSystemJdkInfos (Action? logger = null)
{
logger = logger ?? AndroidSdkInfo.DefaultConsoleLogger;
@@ -295,6 +296,7 @@ static IEnumerable GetConfiguredJdks (Action logger
return GetConfiguredJdkPaths (logger)
.Select (p => TryGetJdkInfo (p, logger, "monodroid-config.xml"))
.Where (jdk => jdk != null)
+ .Select (jdk => jdk!)
.OrderByDescending (jdk => jdk, JdkInfoVersionComparer.Default);
}
@@ -312,6 +314,7 @@ internal static IEnumerable GetMacOSMicrosoftJdks (Action TryGetJdkInfo (p, logger, "$HOME/Library/Developer/Xamarin/jdk"))
.Where (jdk => jdk != null)
+ .Select (jdk => jdk!)
.OrderByDescending (jdk => jdk, JdkInfoVersionComparer.Default);
}
@@ -329,9 +332,9 @@ static IEnumerable GetMacOSMicrosoftJdkPaths ()
return Directory.EnumerateDirectories (jdks);
}
- static JdkInfo TryGetJdkInfo (string path, Action logger, string locator)
+ static JdkInfo? TryGetJdkInfo (string path, Action logger, string locator)
{
- JdkInfo jdk = null;
+ JdkInfo? jdk = null;
try {
jdk = new JdkInfo (path, locator);
}
@@ -366,6 +369,7 @@ static IEnumerable GetLibexecJdks (Action logger)
.Distinct ()
.Select (p => TryGetJdkInfo (p, logger, "`/usr/libexec/java_home -X`"))
.Where (jdk => jdk != null)
+ .Select (jdk => jdk!)
.OrderByDescending (jdk => jdk, JdkInfoVersionComparer.Default);
}
@@ -404,7 +408,8 @@ static IEnumerable GetJavaAlternativesJdks (Action
return GetJavaAlternativesJdkPaths ()
.Distinct ()
.Select (p => TryGetJdkInfo (p, logger, "`/usr/sbin/update-java-alternatives -l`"))
- .Where (jdk => jdk != null);
+ .Where (jdk => jdk != null)
+ .Select (jdk => jdk!);
}
static IEnumerable GetJavaAlternativesJdkPaths ()
@@ -438,6 +443,7 @@ static IEnumerable GetLibJvmJdks (Action logger)
.Distinct ()
.Select (p => TryGetJdkInfo (p, logger, "`ls /usr/lib/jvm/*`"))
.Where (jdk => jdk != null)
+ .Select (jdk => jdk!)
.OrderByDescending (jdk => jdk, JdkInfoVersionComparer.Default);
}
@@ -459,7 +465,8 @@ static IEnumerable GetPathEnvironmentJdks (Action l
{
return GetPathEnvironmentJdkPaths ()
.Select (p => TryGetJdkInfo (p, logger, "$PATH"))
- .Where (jdk => jdk != null);
+ .Where (jdk => jdk != null)
+ .Select (jdk => jdk!);
}
static IEnumerable GetPathEnvironmentJdkPaths ()
@@ -471,7 +478,7 @@ static IEnumerable GetPathEnvironmentJdkPaths ()
// `java -XshowSettings:properties -version 2>&1 | grep java.home` ends with `/jre` on macOS.
// We need the parent dir so we can properly lookup the `include` directories
if (java_home.EndsWith ("jre", StringComparison.OrdinalIgnoreCase)) {
- java_home = Path.GetDirectoryName (java_home);
+ java_home = Path.GetDirectoryName (java_home) ?? "";
}
yield return java_home;
}
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/NullableAttributes.cs b/src/Xamarin.Android.Tools.AndroidSdk/NullableAttributes.cs
new file mode 100644
index 0000000..ba4e92f
--- /dev/null
+++ b/src/Xamarin.Android.Tools.AndroidSdk/NullableAttributes.cs
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Diagnostics.CodeAnalysis
+{
+ /// Specifies that null is allowed as an input even if the corresponding type disallows it.
+ [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class AllowNullAttribute : Attribute
+ { }
+
+ /// Specifies that null is disallowed as an input even if the corresponding type allows it.
+ [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class DisallowNullAttribute : Attribute
+ { }
+
+ /// Specifies that an output may be null even if the corresponding type disallows it.
+ [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class MaybeNullAttribute : Attribute
+ { }
+
+ /// Specifies that an output will not be null even if the corresponding type allows it.
+ [AttributeUsage (AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class NotNullAttribute : Attribute
+ { }
+
+ /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it.
+ [AttributeUsage (AttributeTargets.Parameter, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class MaybeNullWhenAttribute : Attribute
+ {
+ /// Initializes the attribute with the specified return value condition.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter may be null.
+ ///
+ public MaybeNullWhenAttribute (bool returnValue) => ReturnValue = returnValue;
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+ }
+
+ /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it.
+ [AttributeUsage (AttributeTargets.Parameter, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class NotNullWhenAttribute : Attribute
+ {
+ /// Initializes the attribute with the specified return value condition.
+ ///
+ /// The return value condition. If the method returns this value, the associated parameter will not be null.
+ ///
+ public NotNullWhenAttribute (bool returnValue) => ReturnValue = returnValue;
+
+ /// Gets the return value condition.
+ public bool ReturnValue { get; }
+ }
+
+ /// Specifies that the output will be non-null if the named parameter is non-null.
+ [AttributeUsage (AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class NotNullIfNotNullAttribute : Attribute
+ {
+ /// Initializes the attribute with the associated parameter name.
+ ///
+ /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
+ ///
+ public NotNullIfNotNullAttribute (string parameterName) => ParameterName = parameterName;
+
+ /// Gets the associated parameter name.
+ public string ParameterName { get; }
+ }
+
+ /// Applied to a method that will never return under any circumstance.
+ [AttributeUsage (AttributeTargets.Method, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class DoesNotReturnAttribute : Attribute
+ { }
+
+ /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value.
+ [AttributeUsage (AttributeTargets.Parameter, Inherited = false)]
+#if INTERNAL_NULLABLE_ATTRIBUTES
+ internal
+#else
+ public
+#endif
+ sealed class DoesNotReturnIfAttribute : Attribute
+ {
+ /// Initializes the attribute with the specified parameter value.
+ ///
+ /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
+ /// the associated parameter matches this value.
+ ///
+ public DoesNotReturnIfAttribute (bool parameterValue) => ParameterValue = parameterValue;
+
+ /// Gets the condition parameter value.
+ public bool ParameterValue { get; }
+ }
+}
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/OS.cs b/src/Xamarin.Android.Tools.AndroidSdk/OS.cs
index 81e7766..ffb395f 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/OS.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/OS.cs
@@ -10,9 +10,9 @@ public class OS
public readonly static bool IsWindows;
public readonly static bool IsMac;
- internal readonly static string ProgramFilesX86;
+ internal readonly static string? ProgramFilesX86;
- internal readonly static string NativeLibraryFormat;
+ internal readonly static string NativeLibraryFormat = "{0}";
static OS ()
{
@@ -39,7 +39,7 @@ static bool IsRunningOnMac ()
buf = Marshal.AllocHGlobal (8192);
// This is a hacktastic way of getting sysname from uname ()
if (uname (buf) == 0) {
- string os = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (buf);
+ string? os = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (buf);
if (os == "Darwin")
return true;
}
@@ -136,13 +136,13 @@ static extern int RegSetValueExW (UIntPtr hKey, string lpValueName, int lpReserv
uint dwType, IntPtr data, uint cbData);
[DllImport (ADVAPI, CharSet = CharSet.Unicode, SetLastError = true)]
- static extern int RegCreateKeyEx (UIntPtr hKey, string subKey, uint reserved, string @class, uint options,
+ static extern int RegCreateKeyEx (UIntPtr hKey, string subKey, uint reserved, string? @class, uint options,
uint samDesired, IntPtr lpSecurityAttributes, out UIntPtr phkResult, out Disposition lpdwDisposition);
[DllImport ("advapi32.dll", SetLastError = true)]
static extern int RegCloseKey (UIntPtr hKey);
- public static string GetValueString (UIntPtr key, string subkey, string valueName, Wow64 wow64)
+ public static string? GetValueString (UIntPtr key, string subkey, string valueName, Wow64 wow64)
{
UIntPtr regKeyHandle;
uint sam = (uint)Rights.QueryValue + (uint)wow64;
@@ -168,8 +168,8 @@ public static void SetValueString (UIntPtr key, string subkey, string valueName,
uint sam = (uint)(Rights.CreateSubKey | Rights.SetValue) + (uint)wow64;
uint options = (uint) Options.NonVolatile;
Disposition disposition;
- if (RegCreateKeyEx (key, subkey, 0, null, options, sam, IntPtr.Zero, out regKeyHandle, out disposition) != 0) {
- throw new Exception ("Could not open or craete key");
+ if (RegCreateKeyEx (key, subkey, 0, "", options, sam, IntPtr.Zero, out regKeyHandle, out disposition) != 0) {
+ throw new Exception ("Could not open or create key");
}
try {
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/ProcessUtils.cs b/src/Xamarin.Android.Tools.AndroidSdk/ProcessUtils.cs
index 352eb77..19965e2 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/ProcessUtils.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/ProcessUtils.cs
@@ -19,7 +19,7 @@ static ProcessUtils ()
ExecutableFileExtensions = pathExts;
}
- public static async Task StartProcess (ProcessStartInfo psi, TextWriter stdout, TextWriter stderr, CancellationToken cancellationToken, Action onStarted = null)
+ public static async Task StartProcess (ProcessStartInfo psi, TextWriter? stdout, TextWriter? stderr, CancellationToken cancellationToken, Action? onStarted = null)
{
cancellationToken.ThrowIfCancellationRequested ();
psi.UseShellExecute = false;
@@ -47,10 +47,10 @@ public static async Task StartProcess (ProcessStartInfo psi, TextWriter std
// end up writing to the same buffer, or they are the same object.
using (cancellationToken.Register (() => KillProcess (process))) {
if (psi.RedirectStandardOutput)
- output = ReadStreamAsync (process.StandardOutput, TextWriter.Synchronized (stdout));
+ output = ReadStreamAsync (process.StandardOutput, TextWriter.Synchronized (stdout!));
if (psi.RedirectStandardError)
- error = ReadStreamAsync (process.StandardError, TextWriter.Synchronized (stderr));
+ error = ReadStreamAsync (process.StandardError, TextWriter.Synchronized (stderr!));
await Task.WhenAll (new [] { output, error, exit }).ConfigureAwait (false);
}
@@ -89,7 +89,7 @@ static async Task ReadStreamAsync (StreamReader stream, TextWriter destination)
///
/// Executes an Android Sdk tool and returns a result. The result is based on a function of the command output.
///
- public static Task ExecuteToolAsync (string exe, Func result, CancellationToken token, Action onStarted = null)
+ public static Task ExecuteToolAsync (string exe, Func result, CancellationToken token, Action? onStarted = null)
{
var tcs = new TaskCompletionSource ();
@@ -115,12 +115,12 @@ public static Task ExecuteToolAsync (string exe, Func FindExecutablesInPath (string executable)
{
- var path = Environment.GetEnvironmentVariable ("PATH");
+ var path = Environment.GetEnvironmentVariable ("PATH") ?? "";
var pathDirs = path.Split (new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
foreach (var dir in pathDirs) {
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs
index b401fb6..1b10df1 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.IO;
using System.Collections.Generic;
@@ -8,8 +9,8 @@ namespace Xamarin.Android.Tools
{
abstract class AndroidSdkBase
{
- string[] allAndroidSdks = null;
- string[] allAndroidNdks = null;
+ string[]? allAndroidSdks;
+ string[]? allAndroidNdks;
public string[] AllAndroidSdks {
get {
@@ -33,12 +34,12 @@ public AndroidSdkBase (Action logger)
Logger = logger;
}
- public string AndroidSdkPath { get; private set; }
- public string AndroidNdkPath { get; private set; }
- public string JavaSdkPath { get; private set; }
- public string JavaBinPath { get; private set; }
- public string AndroidPlatformToolsPath { get; private set; }
- public string AndroidPlatformToolsPathShort { get; private set; }
+ public string? AndroidSdkPath { get; private set; }
+ public string? AndroidNdkPath { get; private set; }
+ public string? JavaSdkPath { get; private set; }
+ public string? JavaBinPath { get; private set; }
+ public string? AndroidPlatformToolsPath { get; private set; }
+ public string? AndroidPlatformToolsPathShort { get; private set; }
public virtual string Adb { get; protected set; } = "adb";
public virtual string ZipAlign { get; protected set; } = "zipalign";
@@ -50,11 +51,11 @@ public AndroidSdkBase (Action logger)
public abstract string NdkHostPlatform64Bit { get; }
public virtual string Javac { get; protected set; } = "javac";
- public abstract string PreferedAndroidSdkPath { get; }
- public abstract string PreferedAndroidNdkPath { get; }
- public abstract string PreferedJavaSdkPath { get; }
+ public abstract string? PreferedAndroidSdkPath { get; }
+ public abstract string? PreferedAndroidNdkPath { get; }
+ public abstract string? PreferedJavaSdkPath { get; }
- public virtual void Initialize (string androidSdkPath = null, string androidNdkPath = null, string javaSdkPath = null)
+ public virtual void Initialize (string? androidSdkPath = null, string? androidNdkPath = null, string? javaSdkPath = null)
{
androidSdkPath = androidSdkPath ?? PreferedAndroidSdkPath;
androidNdkPath = androidNdkPath ?? PreferedAndroidNdkPath;
@@ -94,12 +95,12 @@ public virtual void Initialize (string androidSdkPath = null, string androidNdkP
protected abstract IEnumerable GetAllAvailableAndroidSdks ();
protected abstract IEnumerable GetAllAvailableAndroidNdks ();
- protected abstract string GetJavaSdkPath ();
+ protected abstract string? GetJavaSdkPath ();
protected abstract string GetShortFormPath (string path);
- public abstract void SetPreferredAndroidSdkPath (string path);
- public abstract void SetPreferredJavaSdkPath (string path);
- public abstract void SetPreferredAndroidNdkPath (string path);
+ public abstract void SetPreferredAndroidSdkPath (string? path);
+ public abstract void SetPreferredJavaSdkPath (string? path);
+ public abstract void SetPreferredAndroidNdkPath (string? path);
public bool IsNdk64Bit { get; private set; }
@@ -110,7 +111,7 @@ public string NdkHostPlatform {
///
/// Checks that a value is the location of an Android SDK.
///
- public bool ValidateAndroidSdkLocation (string loc)
+ public bool ValidateAndroidSdkLocation ([NotNullWhen (true)] string? loc)
{
bool result = !string.IsNullOrEmpty (loc) && ProcessUtils.FindExecutablesInDirectory (Path.Combine (loc, "platform-tools"), Adb).Any ();
Logger (TraceLevel.Verbose, $"{nameof (ValidateAndroidSdkLocation)}: `{loc}`, result={result}");
@@ -120,7 +121,7 @@ public bool ValidateAndroidSdkLocation (string loc)
///
/// Checks that a value is the location of a Java SDK.
///
- public virtual bool ValidateJavaSdkLocation (string loc)
+ public virtual bool ValidateJavaSdkLocation ([NotNullWhen (true)] string? loc)
{
bool result = !string.IsNullOrEmpty (loc) && ProcessUtils.FindExecutablesInDirectory (Path.Combine (loc, "bin"), JarSigner).Any ();
Logger (TraceLevel.Verbose, $"{nameof (ValidateJavaSdkLocation)}: `{loc}`, result={result}");
@@ -130,14 +131,15 @@ public virtual bool ValidateJavaSdkLocation (string loc)
///
/// Checks that a value is the location of an Android SDK.
///
- public bool ValidateAndroidNdkLocation (string loc)
+ public bool ValidateAndroidNdkLocation ([NotNullWhen (true)] string? loc)
{
- bool result = !string.IsNullOrEmpty (loc) && ProcessUtils.FindExecutablesInDirectory (loc, NdkStack).Any ();
+ bool result = !string.IsNullOrEmpty (loc) &&
+ ProcessUtils.FindExecutablesInDirectory (loc!, NdkStack).Any ();
Logger (TraceLevel.Verbose, $"{nameof (ValidateAndroidNdkLocation)}: `{loc}`, result={result}");
return result;
}
- protected static string NullIfEmpty (string s)
+ protected static string? NullIfEmpty (string? s)
{
if (s == null || s.Length != 0)
return s;
@@ -145,7 +147,7 @@ protected static string NullIfEmpty (string s)
return null;
}
- static string GetExecutablePath (string dir, string exe)
+ static string GetExecutablePath (string? dir, string exe)
{
if (string.IsNullOrEmpty (dir))
return exe;
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs
index 0d18f7b..12bd536 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkUnix.cs
@@ -13,8 +13,8 @@ namespace Xamarin.Android.Tools
class AndroidSdkUnix : AndroidSdkBase
{
// See comments above UnixConfigPath for explanation on why these are needed
- static readonly string sudo_user;
- static readonly string user;
+ static readonly string? sudo_user;
+ static readonly string? user;
static readonly bool need_chown;
static AndroidSdkUnix ()
@@ -41,7 +41,7 @@ public override string NdkHostPlatform64Bit {
get { return OS.IsMac ? "darwin-x86_64" : "linux-x86_64"; }
}
- public override string PreferedAndroidSdkPath {
+ public override string? PreferedAndroidSdkPath {
get {
var config_file = GetUnixConfigFile (Logger);
var androidEl = config_file.Root.Element ("android-sdk");
@@ -56,7 +56,7 @@ public override string PreferedAndroidSdkPath {
}
}
- public override string PreferedAndroidNdkPath {
+ public override string? PreferedAndroidNdkPath {
get {
var config_file = GetUnixConfigFile (Logger);
var androidEl = config_file.Root.Element ("android-ndk");
@@ -71,7 +71,7 @@ public override string PreferedAndroidNdkPath {
}
}
- public override string PreferedJavaSdkPath {
+ public override string? PreferedJavaSdkPath {
get {
var config_file = GetUnixConfigFile (Logger);
var javaEl = config_file.Root.Element ("java-sdk");
@@ -90,7 +90,7 @@ protected override IEnumerable GetAllAvailableAndroidSdks ()
{
var preferedSdkPath = PreferedAndroidSdkPath;
if (!string.IsNullOrEmpty (preferedSdkPath))
- yield return preferedSdkPath;
+ yield return preferedSdkPath!;
// Look in PATH
foreach (var adb in ProcessUtils.FindExecutablesInPath (Adb)) {
@@ -108,7 +108,7 @@ protected override IEnumerable GetAllAvailableAndroidSdks ()
yield return macSdkPath;
}
- protected override string GetJavaSdkPath ()
+ protected override string? GetJavaSdkPath ()
{
return JdkInfo.GetKnownSystemJdkInfos (Logger).FirstOrDefault ()?.HomePath;
}
@@ -117,7 +117,7 @@ protected override IEnumerable GetAllAvailableAndroidNdks ()
{
var preferedNdkPath = PreferedAndroidNdkPath;
if (!string.IsNullOrEmpty (preferedNdkPath))
- yield return preferedNdkPath;
+ yield return preferedNdkPath!;
// Look in PATH
foreach (var ndkStack in ProcessUtils.FindExecutablesInPath (NdkStack)) {
@@ -133,7 +133,7 @@ protected override string GetShortFormPath (string path)
return path;
}
- public override void SetPreferredAndroidSdkPath (string path)
+ public override void SetPreferredAndroidSdkPath (string? path)
{
path = NullIfEmpty (path);
@@ -149,7 +149,7 @@ public override void SetPreferredAndroidSdkPath (string path)
SaveConfig (doc);
}
- public override void SetPreferredJavaSdkPath (string path)
+ public override void SetPreferredJavaSdkPath (string? path)
{
path = NullIfEmpty (path);
@@ -165,7 +165,7 @@ public override void SetPreferredJavaSdkPath (string path)
SaveConfig (doc);
}
- public override void SetPreferredAndroidNdkPath (string path)
+ public override void SetPreferredAndroidNdkPath (string? path)
{
path = NullIfEmpty (path);
@@ -184,11 +184,11 @@ public override void SetPreferredAndroidNdkPath (string path)
void SaveConfig (XDocument doc)
{
string cfg = UnixConfigPath;
- List created = null;
+ List ? created = null;
if (!File.Exists (cfg)) {
- string dir = Path.GetDirectoryName (cfg);
- if (!Directory.Exists (dir)) {
+ string? dir = Path.GetDirectoryName (cfg);
+ if (dir != null && !Directory.Exists (dir)) {
Directory.CreateDirectory (dir);
AddToList (dir);
}
@@ -245,7 +245,7 @@ private static string UnixConfigPath {
internal static XDocument GetUnixConfigFile (Action logger)
{
var file = UnixConfigPath;
- XDocument doc = null;
+ XDocument? doc = null;
if (File.Exists (file)) {
try {
doc = XDocument.Load (file);
@@ -270,7 +270,7 @@ internal static XDocument GetUnixConfigFile (Action logger)
return doc;
}
- void FixOwnership (List paths)
+ void FixOwnership (List? paths)
{
if (!need_chown || paths == null || paths.Count == 0)
return;
@@ -278,7 +278,7 @@ void FixOwnership (List paths)
var stdout = new StringWriter ();
var stderr = new StringWriter ();
var args = new List {
- QuoteString (sudo_user)
+ QuoteString (sudo_user!)
};
foreach (string p in paths)
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs
index 792c658..c363703 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs
+++ b/src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkWindows.cs
@@ -32,7 +32,7 @@ public AndroidSdkWindows (Action logger)
public override string NdkHostPlatform64Bit { get { return "windows-x86_64"; } }
public override string Javac { get; protected set; } = "javac.exe";
- public override string PreferedAndroidSdkPath {
+ public override string? PreferedAndroidSdkPath {
get {
var wow = RegistryEx.Wow64.Key32;
var regKey = GetMDRegistryKey ();
@@ -41,7 +41,7 @@ public override string PreferedAndroidSdkPath {
return null;
}
}
- public override string PreferedAndroidNdkPath {
+ public override string? PreferedAndroidNdkPath {
get {
var wow = RegistryEx.Wow64.Key32;
var regKey = GetMDRegistryKey ();
@@ -50,7 +50,7 @@ public override string PreferedAndroidNdkPath {
return null;
}
}
- public override string PreferedJavaSdkPath {
+ public override string? PreferedJavaSdkPath {
get {
var wow = RegistryEx.Wow64.Key32;
var regKey = GetMDRegistryKey ();
@@ -77,16 +77,16 @@ protected override IEnumerable GetAllAvailableAndroidSdks ()
// Check for the key the user gave us in the VS/addin options
foreach (var root in roots)
if (CheckRegistryKeyForExecutable (root, regKey, MDREG_ANDROID_SDK, wow, "platform-tools", Adb))
- yield return RegistryEx.GetValueString (root, regKey, MDREG_ANDROID_SDK, wow);
+ yield return RegistryEx.GetValueString (root, regKey, MDREG_ANDROID_SDK, wow) ?? "";
// Check for the key written by the Xamarin installer
if (CheckRegistryKeyForExecutable (RegistryEx.CurrentUser, XAMARIN_ANDROID_INSTALLER_PATH, XAMARIN_ANDROID_INSTALLER_KEY, wow, "platform-tools", Adb))
- yield return RegistryEx.GetValueString (RegistryEx.CurrentUser, XAMARIN_ANDROID_INSTALLER_PATH, XAMARIN_ANDROID_INSTALLER_KEY, wow);
+ yield return RegistryEx.GetValueString (RegistryEx.CurrentUser, XAMARIN_ANDROID_INSTALLER_PATH, XAMARIN_ANDROID_INSTALLER_KEY, wow) ?? "";
// Check for the key written by the Android SDK installer
foreach (var root in roots)
if (CheckRegistryKeyForExecutable (root, ANDROID_INSTALLER_PATH, ANDROID_INSTALLER_KEY, wow, "platform-tools", Adb))
- yield return RegistryEx.GetValueString (root, ANDROID_INSTALLER_PATH, ANDROID_INSTALLER_KEY, wow);
+ yield return RegistryEx.GetValueString (root, ANDROID_INSTALLER_PATH, ANDROID_INSTALLER_KEY, wow) ?? "";
// Check some hardcoded paths for good measure
var paths = new string [] {
@@ -94,7 +94,7 @@ protected override IEnumerable GetAllAvailableAndroidSdks ()
Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), "Android", "android-sdk"),
Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFilesX86), "Android", "android-sdk-windows"),
!string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("ProgramW6432"))
- ? Path.Combine (Environment.GetEnvironmentVariable ("ProgramW6432"), "Android", "android-sdk")
+ ? Path.Combine (Environment.GetEnvironmentVariable ("ProgramW6432") ?? "", "Android", "android-sdk")
: Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles), "Android", "android-sdk"),
Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), "Android", "android-sdk"),
Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData), "Android", "android-sdk"),
@@ -106,7 +106,7 @@ protected override IEnumerable GetAllAvailableAndroidSdks ()
yield return basePath;
}
- protected override string GetJavaSdkPath ()
+ protected override string? GetJavaSdkPath ()
{
var jdk = GetJdkInfos (Logger).FirstOrDefault ();
return jdk?.HomePath;
@@ -114,9 +114,9 @@ protected override string GetJavaSdkPath ()
internal static IEnumerable GetJdkInfos (Action logger)
{
- JdkInfo TryGetJdkInfo (string path, string locator)
+ JdkInfo? TryGetJdkInfo (string path, string locator)
{
- JdkInfo jdk = null;
+ JdkInfo? jdk = null;
try {
jdk = new JdkInfo (path, locator);
}
@@ -131,6 +131,7 @@ IEnumerable ToJdkInfos (IEnumerable paths, string locator)
{
return paths.Select (p => TryGetJdkInfo (p, locator))
.Where (jdk => jdk != null)
+ .Select(jdk => jdk!)
.OrderByDescending (jdk => jdk, JdkInfoVersionComparer.Default);
}
@@ -161,7 +162,7 @@ private static IEnumerable GetPreferredJdkPaths ()
foreach (var root in roots) {
if (CheckRegistryKeyForExecutable (root, regKey, MDREG_JAVA_SDK, wow, "bin", _JarSigner))
- yield return RegistryEx.GetValueString (root, regKey, MDREG_JAVA_SDK, wow);
+ yield return RegistryEx.GetValueString (root, regKey, MDREG_JAVA_SDK, wow) ?? "";
}
}
@@ -174,7 +175,7 @@ private static IEnumerable GetOpenJdkPaths ()
foreach (var wow in wows) {
if (CheckRegistryKeyForExecutable (root, subKey, valueName, wow, "bin", _JarSigner))
- yield return RegistryEx.GetValueString (root, subKey, valueName, wow);
+ yield return RegistryEx.GetValueString (root, subKey, valueName, wow) ?? "";
}
}
@@ -196,7 +197,7 @@ private static IEnumerable GetKnownOpenJdkPaths ()
if (Directory.Exists (rootPath)) {
foreach (var directoryName in Directory.EnumerateDirectories (rootPath, $"{JdkFolderNamePattern}*").ToList ()) {
var versionString = directoryName.Replace ($"{rootPath}\\{JdkFolderNamePattern}", string.Empty);
- if (Version.TryParse (versionString, out Version ver)) {
+ if (Version.TryParse (versionString, out Version? ver)) {
paths.Add (new Tuple(directoryName, ver));
}
}
@@ -220,13 +221,13 @@ private static IEnumerable GetOracleJdkPaths ()
// No matter what the CurrentVersion is, look for 1.6 or 1.7 or 1.8
if (CheckRegistryKeyForExecutable (RegistryEx.LocalMachine, subkey + "\\" + "1.8", "JavaHome", wow64, "bin", _JarSigner))
- yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.8", "JavaHome", wow64);
+ yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.8", "JavaHome", wow64) ?? "";
if (CheckRegistryKeyForExecutable (RegistryEx.LocalMachine, subkey + "\\" + "1.7", "JavaHome", wow64, "bin", _JarSigner))
- yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.7", "JavaHome", wow64);
+ yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.7", "JavaHome", wow64) ?? "";
if (CheckRegistryKeyForExecutable (RegistryEx.LocalMachine, subkey + "\\" + "1.6", "JavaHome", wow64, "bin", _JarSigner))
- yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.6", "JavaHome", wow64);
+ yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.6", "JavaHome", wow64) ?? "";
}
}
}
@@ -244,7 +245,7 @@ protected override IEnumerable GetAllAvailableAndroidNdks ()
var sdks = GetAllAvailableAndroidSdks().ToList();
if (!string.IsNullOrEmpty(AndroidSdkPath))
- sdks.Add(AndroidSdkPath);
+ sdks.Add (AndroidSdkPath!);
foreach(var sdk in sdks.Distinct())
if (Directory.Exists(ndk = Path.Combine(sdk, "ndk-bundle")))
@@ -254,7 +255,7 @@ protected override IEnumerable GetAllAvailableAndroidNdks ()
// Check for the key the user gave us in the VS/addin options
foreach (var root in roots)
if (CheckRegistryKeyForExecutable (root, regKey, MDREG_ANDROID_NDK, wow, ".", NdkStack))
- yield return RegistryEx.GetValueString (root, regKey, MDREG_ANDROID_NDK, wow);
+ yield return RegistryEx.GetValueString (root, regKey, MDREG_ANDROID_NDK, wow) ?? "";
/*
// Check for the key written by the Xamarin installer
@@ -267,7 +268,7 @@ protected override IEnumerable GetAllAvailableAndroidNdks ()
var vs_default = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData), "Microsoft", "AndroidNDK");
var vs_default32bit = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData), "Microsoft", "AndroidNDK32");
var vs_2017_default = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData), "Microsoft", "AndroidNDK64");
- var android_default = Path.Combine (OS.ProgramFilesX86, "Android");
+ var android_default = Path.Combine (OS.ProgramFilesX86 ?? "", "Android");
var cdrive_default = @"C:\";
foreach (var basePath in new string [] {xamarin_private, android_default, vs_default, vs_default32bit, vs_2017_default, cdrive_default})
@@ -282,19 +283,19 @@ protected override string GetShortFormPath (string path)
return KernelEx.GetShortPathName (path);
}
- public override void SetPreferredAndroidSdkPath (string path)
+ public override void SetPreferredAndroidSdkPath (string? path)
{
var regKey = GetMDRegistryKey ();
RegistryEx.SetValueString (RegistryEx.CurrentUser, regKey, MDREG_ANDROID_SDK, path ?? "", RegistryEx.Wow64.Key32);
}
- public override void SetPreferredJavaSdkPath (string path)
+ public override void SetPreferredJavaSdkPath (string? path)
{
var regKey = GetMDRegistryKey ();
RegistryEx.SetValueString (RegistryEx.CurrentUser, regKey, MDREG_JAVA_SDK, path ?? "", RegistryEx.Wow64.Key32);
}
- public override void SetPreferredAndroidNdkPath (string path)
+ public override void SetPreferredAndroidNdkPath (string? path)
{
var regKey = GetMDRegistryKey ();
RegistryEx.SetValueString (RegistryEx.CurrentUser, regKey, MDREG_ANDROID_NDK, path ?? "", RegistryEx.Wow64.Key32);
@@ -323,7 +324,7 @@ private static bool CheckRegistryKeyForExecutable (UIntPtr key, string subkey, s
}
#endregion
- public override void Initialize (string androidSdkPath = null, string androidNdkPath = null, string javaSdkPath = null)
+ public override void Initialize (string? androidSdkPath = null, string? androidNdkPath = null, string? javaSdkPath = null)
{
base.Initialize (androidSdkPath, androidNdkPath, javaSdkPath);
@@ -335,7 +336,7 @@ public override void Initialize (string androidSdkPath = null, string androidNdk
var javaBinPath = this.JavaBinPath;
if (!string.IsNullOrEmpty (javaBinPath)) {
- var environmentPath = Environment.GetEnvironmentVariable ("PATH");
+ var environmentPath = Environment.GetEnvironmentVariable ("PATH") ?? "";
if (!environmentPath.Contains (javaBinPath)) {
var processPath = string.Concat (javaBinPath, Path.PathSeparator, environmentPath);
Environment.SetEnvironmentVariable ("PATH", processPath);
diff --git a/src/Xamarin.Android.Tools.AndroidSdk/Xamarin.Android.Tools.AndroidSdk.csproj b/src/Xamarin.Android.Tools.AndroidSdk/Xamarin.Android.Tools.AndroidSdk.csproj
index 02aec41..81a7a74 100644
--- a/src/Xamarin.Android.Tools.AndroidSdk/Xamarin.Android.Tools.AndroidSdk.csproj
+++ b/src/Xamarin.Android.Tools.AndroidSdk/Xamarin.Android.Tools.AndroidSdk.csproj
@@ -1,7 +1,10 @@
- netstandard2.0
+ netstandard2.0;netcoreapp3.1
+ 8.0
+ enable
+ INTERNAL_NULLABLE_ATTRIBUTES
true
..\..\product.snk
Xamarin.Android.Tools
@@ -13,12 +16,12 @@
Xamarin;Xamarin.Android
-
- ..\..\bin\Debug
-
+
+
+
-
- ..\..\bin\Release
+
+ $(ToolOutputFullPath)
diff --git a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj
index b2de219..2de72a8 100644
--- a/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj
+++ b/tests/Xamarin.Android.Tools.AndroidSdk-Tests/Xamarin.Android.Tools.AndroidSdk-Tests.csproj
@@ -1,17 +1,13 @@
- net461
+ net461;netcoreapp3.1
false
false
-
- ..\..\bin\TestDebug
-
-
-
- ..\..\bin\TestRelease
+
+ $(TestOutputFullPath)