@@ -18,6 +18,7 @@ class AndroidSdkWindows : AndroidSdkBase
1818 const string ANDROID_INSTALLER_KEY = "Path" ;
1919 const string XAMARIN_ANDROID_INSTALLER_PATH = @"SOFTWARE\Xamarin\MonoAndroid" ;
2020 const string XAMARIN_ANDROID_INSTALLER_KEY = "PrivateAndroidSdkPath" ;
21+ const string MICROSOFT_OPENJDK_PATH = @"SOFTWARE\Microsoft\JDK" ;
2122
2223 public AndroidSdkWindows ( Action < TraceLevel , string > logger )
2324 : base ( logger )
@@ -131,8 +132,9 @@ IEnumerable<JdkInfo> ToJdkInfos (IEnumerable<string> paths, string locator)
131132 }
132133
133134 return ToJdkInfos ( GetPreferredJdkPaths ( ) , "Preferred Registry" )
134- . Concat ( ToJdkInfos ( GetOpenJdkPaths ( ) , "OpenJDK" ) )
135- . Concat ( ToJdkInfos ( GetKnownOpenJdkPaths ( ) , "Well-known OpenJDK paths" ) )
135+ . Concat ( ToJdkInfos ( GetMicrosoftOpenJdkFilesystemPaths ( ) , "Microsoft OpenJDK Filesystem" ) )
136+ . Concat ( ToJdkInfos ( GetMicrosoftOpenJdkRegistryPaths ( ) , "Microsoft OpenJDK Registry" ) )
137+ . Concat ( ToJdkInfos ( GetVSAndroidJdkPaths ( ) , @"HKLM\SOFTWARE\Microsoft\VisualStudio\Android@JavaHome" ) )
136138 . Concat ( ToJdkInfos ( GetOracleJdkPaths ( ) , "Oracle JDK" ) )
137139 ;
138140 }
@@ -150,7 +152,7 @@ private static IEnumerable<string> GetPreferredJdkPaths ()
150152 }
151153 }
152154
153- private static IEnumerable < string > GetOpenJdkPaths ( )
155+ private static IEnumerable < string > GetVSAndroidJdkPaths ( )
154156 {
155157 var root = RegistryEx . LocalMachine ;
156158 var wows = new [ ] { RegistryEx . Wow64 . Key32 , RegistryEx . Wow64 . Key64 } ;
@@ -163,28 +165,24 @@ private static IEnumerable<string> GetOpenJdkPaths ()
163165 }
164166 }
165167
166- /// <summary>
167- /// Locate OpenJDK installations by well known path.
168- /// </summary>
169- /// <returns>List of valid OpenJDK paths in version descending order.</returns>
170- private static IEnumerable < string > GetKnownOpenJdkPaths ( )
168+ static IEnumerable < string > GetMicrosoftOpenJdkFilesystemPaths ( )
171169 {
172- string JdkFolderNamePattern = "microsoft_dist_openjdk_ " ;
170+ const string JdkFolderNamePrefix = "jdk- " ;
173171
174172 var paths = new List < Tuple < string , Version > > ( ) ;
175173 var rootPaths = new List < string > {
176- Path . Combine ( Environment . ExpandEnvironmentVariables ( "%ProgramW6432%" ) , "Android" , "jdk ") ,
174+ Path . Combine ( Environment . ExpandEnvironmentVariables ( "%ProgramW6432%" ) , "Microsoft " ) ,
177175 Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . ProgramFilesX86 ) , "Android" , "jdk" ) ,
178176 } ;
179177
180178 foreach ( var rootPath in rootPaths ) {
181- if ( Directory . Exists ( rootPath ) ) {
182- foreach ( var directoryName in Directory . EnumerateDirectories ( rootPath , $ " { JdkFolderNamePattern } *" ) . ToList ( ) ) {
183- var versionString = directoryName . Replace ( $ "{ rootPath } \\ { JdkFolderNamePattern } " , string . Empty ) ;
184- if ( Version . TryParse ( versionString , out Version ? ver ) ) {
185- paths . Add ( new Tuple < string , Version > ( directoryName , ver ) ) ;
186- }
187- }
179+ if ( ! Directory . Exists ( rootPath ) )
180+ continue ;
181+ foreach ( var directoryName in Directory . EnumerateDirectories ( rootPath , $ "{ JdkFolderNamePrefix } *" ) ) {
182+ var version = ExtractVersion ( directoryName , JdkFolderNamePrefix ) ;
183+ if ( version == null )
184+ continue ;
185+ paths . Add ( Tuple . Create ( directoryName , version ) ) ;
188186 }
189187 }
190188
@@ -193,6 +191,59 @@ private static IEnumerable<string> GetKnownOpenJdkPaths ()
193191 . Select ( openJdk => openJdk . Item1 ) ;
194192 }
195193
194+ static IEnumerable < string > GetMicrosoftOpenJdkRegistryPaths ( )
195+ {
196+ var paths = new List < ( Version version , string path ) > ( ) ;
197+ var roots = new [ ] { RegistryEx . CurrentUser , RegistryEx . LocalMachine } ;
198+ var wows = new [ ] { RegistryEx . Wow64 . Key32 , RegistryEx . Wow64 . Key64 } ;
199+ foreach ( var root in roots )
200+ foreach ( var wow in wows ) {
201+ foreach ( var subkeyName in RegistryEx . EnumerateSubkeys ( root , MICROSOFT_OPENJDK_PATH , wow ) ) {
202+ if ( ! Version . TryParse ( subkeyName , out var version ) )
203+ continue ;
204+ var msiKey = $@ "{ MICROSOFT_OPENJDK_PATH } \{ subkeyName } \hotspot\MSI";
205+ var path = RegistryEx . GetValueString ( root , msiKey , "Path" , wow ) ;
206+ if ( path == null )
207+ continue ;
208+ paths . Add ( ( version , path ) ) ;
209+ }
210+ }
211+
212+ return paths . OrderByDescending ( e => e . version )
213+ . Select ( e => e . path ) ;
214+ }
215+
216+ internal static Version ? ExtractVersion ( string path , string prefix )
217+ {
218+ var name = Path . GetFileName ( path ) ;
219+ if ( name . Length <= prefix . Length )
220+ return null ;
221+ if ( ! name . StartsWith ( prefix , StringComparison . OrdinalIgnoreCase ) )
222+ return null ;
223+
224+ var start = prefix . Length ;
225+ while ( start < name . Length && ! char . IsDigit ( name , start ) ) {
226+ ++ start ;
227+ }
228+ if ( start == name . Length )
229+ return null ;
230+
231+ name = name . Substring ( start ) ;
232+ int end = 0 ;
233+ while ( end < name . Length &&
234+ ( char . IsDigit ( name [ end ] ) || name [ end ] == '.' ) ) {
235+ end ++ ;
236+ }
237+
238+ do {
239+ if ( Version . TryParse ( name . Substring ( 0 , end ) , out var v ) )
240+ return v ;
241+ end = name . LastIndexOf ( '.' , end - 1 ) ;
242+ } while ( end > 0 ) ;
243+
244+ return null ;
245+ }
246+
196247 private static IEnumerable < string > GetOracleJdkPaths ( )
197248 {
198249 string subkey = @"SOFTWARE\JavaSoft\Java Development Kit" ;
0 commit comments