[flutter_tools] Refactor Android Studio Detection on Windows (support 4.x and 202x releases detection) (#86624)
diff --git a/packages/flutter_tools/lib/src/android/android_studio.dart b/packages/flutter_tools/lib/src/android/android_studio.dart
index fcdb9df..c15cad0 100644
--- a/packages/flutter_tools/lib/src/android/android_studio.dart
+++ b/packages/flutter_tools/lib/src/android/android_studio.dart
@@ -10,6 +10,7 @@
import '../convert.dart';
import '../globals_null_migrated.dart' as globals;
import '../ios/plist_parser.dart';
+import 'android_studio_validator.dart';
// Android Studio layout:
@@ -373,51 +374,37 @@
}
}
- // 4.1 has a different location for AndroidStudio installs on Windows.
+ // Discover Android Studio > 4.1
if (globals.platform.isWindows && globals.platform.environment.containsKey('LOCALAPPDATA')) {
- final File homeDot = globals.fs.file(globals.fs.path.join(
- globals.platform.environment['LOCALAPPDATA']!,
- 'Google',
- 'AndroidStudio4.1',
- '.home',
- ));
- if (homeDot.existsSync()) {
- final String installPath = homeDot.readAsStringSync();
- if (globals.fs.isDirectorySync(installPath)) {
- final AndroidStudio studio = AndroidStudio(
- installPath,
- version: Version(4, 1, 0),
- studioAppName: 'Android Studio 4.1',
- );
- if (studio != null && !_hasStudioAt(studio.directory, newerThan: studio.version)) {
- studios.removeWhere((AndroidStudio other) => other.directory == studio.directory);
- studios.add(studio);
- }
- }
+ final Directory cacheDir = globals.fs.directory(globals.fs.path.join(globals.platform.environment['LOCALAPPDATA']!, 'Google'));
+ if (!cacheDir.existsSync()) {
+ return studios;
}
- }
+ for (final Directory dir in cacheDir.listSync().whereType<Directory>()) {
+ final String name = globals.fs.path.basename(dir.path);
+ AndroidStudioValidator.idToTitle.forEach((String id, String title) {
+ if (name.startsWith(id)) {
+ final String version = name.substring(id.length);
+ String? installPath;
- // 4.2 has a different location for AndroidStudio installs on Windows.
- if (globals.platform.isWindows && globals.platform.environment.containsKey('LOCALAPPDATA')) {
- final File homeDot = globals.fs.file(globals.fs.path.join(
- globals.platform.environment['LOCALAPPDATA']!,
- 'Google',
- 'AndroidStudio4.2',
- '.home',
- ));
- if (homeDot.existsSync()) {
- final String installPath = homeDot.readAsStringSync();
- if (globals.fs.isDirectorySync(installPath)) {
- final AndroidStudio studio = AndroidStudio(
- installPath,
- version: Version(4, 2, 0),
- studioAppName: 'Android Studio 4.2',
- );
- if (studio != null && !_hasStudioAt(studio.directory, newerThan: studio.version)) {
- studios.removeWhere((AndroidStudio other) => other.directory == studio.directory);
- studios.add(studio);
+ try {
+ installPath = globals.fs.file(globals.fs.path.join(dir.path, '.home')).readAsStringSync();
+ } on FileSystemException {
+ // ignored
+ }
+ if (installPath != null && globals.fs.isDirectorySync(installPath)) {
+ final AndroidStudio studio = AndroidStudio(
+ installPath,
+ version: Version.parse(version),
+ studioAppName: title,
+ );
+ if (studio != null && !_hasStudioAt(studio.directory, newerThan: studio.version)) {
+ studios.removeWhere((AndroidStudio other) => other.directory == studio.directory);
+ studios.add(studio);
+ }
+ }
}
- }
+ });
}
}
diff --git a/packages/flutter_tools/lib/src/android/android_studio_validator.dart b/packages/flutter_tools/lib/src/android/android_studio_validator.dart
index 013cc7e..8ff88ac 100644
--- a/packages/flutter_tools/lib/src/android/android_studio_validator.dart
+++ b/packages/flutter_tools/lib/src/android/android_studio_validator.dart
@@ -11,6 +11,11 @@
import '../intellij/intellij.dart';
import 'android_studio.dart';
+const String _androidStudioTitle = 'Android Studio';
+const String _androidStudioId = 'AndroidStudio';
+const String _androidStudioPreviewTitle = 'Android Studio Preview';
+const String _androidStudioPreviewId = 'AndroidStudioPreview';
+
class AndroidStudioValidator extends DoctorValidator {
AndroidStudioValidator(this._studio, { required FileSystem fileSystem })
: _fileSystem = fileSystem,
@@ -19,6 +24,11 @@
final AndroidStudio _studio;
final FileSystem _fileSystem;
+ static const Map<String, String> idToTitle = <String, String>{
+ _androidStudioId: _androidStudioTitle,
+ _androidStudioPreviewId: _androidStudioPreviewTitle,
+ };
+
static List<DoctorValidator> allValidators(Config config, Platform platform, FileSystem fileSystem, UserMessages userMessages) {
final List<AndroidStudio> studios = AndroidStudio.allInstalled();
return <DoctorValidator>[
diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart
index 177574f..7ccecee 100644
--- a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart
+++ b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart
@@ -402,7 +402,7 @@
final AndroidStudio studio = AndroidStudio.allInstalled().single;
expect(studio.version, Version(4, 1, 0));
- expect(studio.studioAppName, 'Android Studio 4.1');
+ expect(studio.studioAppName, 'Android Studio');
}, overrides: <Type, Generator>{
Platform: () => windowsPlatform,
FileSystem: () => windowsFileSystem,
@@ -420,7 +420,25 @@
final AndroidStudio studio = AndroidStudio.allInstalled().single;
expect(studio.version, Version(4, 2, 0));
- expect(studio.studioAppName, 'Android Studio 4.2');
+ expect(studio.studioAppName, 'Android Studio');
+ }, overrides: <Type, Generator>{
+ Platform: () => windowsPlatform,
+ FileSystem: () => windowsFileSystem,
+ ProcessManager: () => FakeProcessManager.any(),
+ });
+
+ testUsingContext('Can discover Android Studio 2020.3 location on Windows', () {
+ windowsFileSystem.file(r'C:\Users\Dash\AppData\Local\Google\AndroidStudio2020.3\.home')
+ ..createSync(recursive: true)
+ ..writeAsStringSync(r'C:\Program Files\AndroidStudio');
+ windowsFileSystem
+ .directory(r'C:\Program Files\AndroidStudio')
+ .createSync(recursive: true);
+
+ final AndroidStudio studio = AndroidStudio.allInstalled().single;
+
+ expect(studio.version, Version(2020, 3, 0));
+ expect(studio.studioAppName, 'Android Studio');
}, overrides: <Type, Generator>{
Platform: () => windowsPlatform,
FileSystem: () => windowsFileSystem,
@@ -463,6 +481,24 @@
ProcessManager: () => FakeProcessManager.any(),
});
+ testUsingContext('Does not discover Android Studio 2020.3 location on Windows if LOCALAPPDATA is null', () {
+ windowsFileSystem.file(r'C:\Users\Dash\AppData\Local\Google\AndroidStudio2020.3\.home')
+ ..createSync(recursive: true)
+ ..writeAsStringSync(r'C:\Program Files\AndroidStudio');
+ windowsFileSystem
+ .directory(r'C:\Program Files\AndroidStudio')
+ .createSync(recursive: true);
+
+ expect(AndroidStudio.allInstalled(), isEmpty);
+ }, overrides: <Type, Generator>{
+ Platform: () => FakePlatform(
+ operatingSystem: 'windows',
+ environment: <String, String>{}, // Does not include LOCALAPPDATA
+ ),
+ FileSystem: () => windowsFileSystem,
+ ProcessManager: () => FakeProcessManager.any(),
+ });
+
group('Installation detection on Linux', () {
FileSystemUtils fsUtils;