Skip to content
Merged
17 changes: 2 additions & 15 deletions packages/flutter_tools/lib/src/android/android_workflow.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:process/process.dart';

import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/platform.dart';
Expand All @@ -18,7 +17,6 @@ import '../convert.dart';
import '../doctor_validator.dart';
import '../features.dart';
import 'android_sdk.dart';
import 'android_studio.dart';
import 'java.dart';

const int kAndroidSdkMinVersion = 29;
Expand Down Expand Up @@ -226,29 +224,23 @@ class AndroidLicenseValidator extends DoctorValidator {
required Java? java,
required AndroidSdk? androidSdk,
required Platform platform,
required FileSystem fileSystem,
required ProcessManager processManager,
required Logger logger,
required AndroidStudio? androidStudio,
required Stdio stdio,
required UserMessages userMessages,
}) : _java = java,
_androidSdk = androidSdk,
_platform = platform,
_fileSystem = fileSystem,
_processManager = processManager,
_logger = logger,
_androidStudio = androidStudio,
_stdio = stdio,
_userMessages = userMessages,
super('Android license subvalidator');

final Java? _java;
final AndroidSdk? _androidSdk;
final AndroidStudio? _androidStudio;
final Stdio _stdio;
final Platform _platform;
final FileSystem _fileSystem;
final ProcessManager _processManager;
final Logger _logger;
final UserMessages _userMessages;
Expand Down Expand Up @@ -287,13 +279,8 @@ class AndroidLicenseValidator extends DoctorValidator {
}

Future<bool> _checkJavaVersionNoOutput() async {
final String? javaBinary = Java.find(
logger: _logger,
androidStudio: _androidStudio,
fileSystem: _fileSystem,
platform: _platform,
processManager: _processManager,
)?.binaryPath;
final String? javaBinary = _java?.binaryPath;

if (javaBinary == null) {
return false;
}
Expand Down
9 changes: 9 additions & 0 deletions packages/flutter_tools/lib/src/android/java.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:process/process.dart';

import '../base/config.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/os.dart';
Expand Down Expand Up @@ -52,6 +53,7 @@ class Java {
///
/// Returns null if no java binary could be found.
static Java? find({
required Config config,
required AndroidStudio? androidStudio,
required Logger logger,
required FileSystem fileSystem,
Expand All @@ -65,6 +67,7 @@ class Java {
processManager: processManager
);
final String? home = _findJavaHome(
config: config,
logger: logger,
androidStudio: androidStudio,
platform: platform
Expand Down Expand Up @@ -181,10 +184,16 @@ class Java {
}

String? _findJavaHome({
required Config config,
required Logger logger,
required AndroidStudio? androidStudio,
required Platform platform,
}) {
final Object? configured = config.getValue('jdk-dir');
if (configured != null) {
return configured as String;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, doesn't need to be in this PR, but should we move these casts to be methods on the Config class? That way it will be easier and more obvious how to refactor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

final String? androidStudioJavaPath = androidStudio?.javaPath;
if (androidStudioJavaPath != null) {
return androidStudioJavaPath;
Expand Down
30 changes: 22 additions & 8 deletions packages/flutter_tools/lib/src/commands/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import '../../src/android/android_sdk.dart';
import '../../src/android/android_studio.dart';
import '../android/java.dart';
import '../base/common.dart';
import '../convert.dart';
import '../features.dart';
Expand All @@ -19,7 +20,12 @@ class ConfigCommand extends FlutterCommand {
negatable: false,
help: 'Clear the saved development certificate choice used to sign apps for iOS device deployment.');
argParser.addOption('android-sdk', help: 'The Android SDK directory.');
argParser.addOption('android-studio-dir', help: 'The Android Studio install directory. If unset, flutter will search for valid installs at well-known locations.');
argParser.addOption('android-studio-dir', help: 'The Android Studio installation directory. If unset, flutter will search for valid installations at well-known locations.');
argParser.addOption('jdk-dir', help: 'The Java Development Kit (JDK) installation directory. '
'If unset, flutter will search for one in the following order:\n'
' 1) the JDK bundled with the latest installation of Android Studio,\n'
' 2) the JDK found at the directory found in the JAVA_HOME environment variable, and\n'
" 3) the directory containing the java binary found in the user's path.");
argParser.addOption('build-dir', help: 'The relative path to override a projects build directory.',
valueHelp: 'out/');
argParser.addFlag('machine',
Expand Down Expand Up @@ -101,7 +107,7 @@ class ConfigCommand extends FlutterCommand {

@override
Future<FlutterCommandResult> runCommand() async {
final List<String> rest = argResults?.rest ?? <String>[];
final List<String> rest = argResults!.rest;
if (rest.isNotEmpty) {
throwToolExit(exitCode: 2,
'error: flutter config: Too many arguments.\n'
Expand All @@ -126,7 +132,7 @@ class ConfigCommand extends FlutterCommand {
return FlutterCommandResult.success();
}

if (argResults?.wasParsed('analytics') ?? false) {
if (argResults!.wasParsed('analytics')) {
final bool value = boolArg('analytics');
// The tool sends the analytics event *before* toggling the flag
// intentionally to be sure that opt-out events are sent correctly.
Expand All @@ -146,19 +152,23 @@ class ConfigCommand extends FlutterCommand {
await globals.analytics.setTelemetry(value);
}

if (argResults?.wasParsed('android-sdk') ?? false) {
if (argResults!.wasParsed('android-sdk')) {
_updateConfig('android-sdk', stringArg('android-sdk')!);
}

if (argResults?.wasParsed('android-studio-dir') ?? false) {
if (argResults!.wasParsed('android-studio-dir')) {
_updateConfig('android-studio-dir', stringArg('android-studio-dir')!);
}

if (argResults?.wasParsed('clear-ios-signing-cert') ?? false) {
if (argResults!.wasParsed('jdk-dir')) {
_updateConfig('jdk-dir', stringArg('jdk-dir')!);
}

if (argResults!.wasParsed('clear-ios-signing-cert')) {
_updateConfig('ios-signing-cert', '');
}

if (argResults?.wasParsed('build-dir') ?? false) {
if (argResults!.wasParsed('build-dir')) {
final String buildDir = stringArg('build-dir')!;
if (globals.fs.path.isAbsolute(buildDir)) {
throwToolExit('build-dir should be a relative path');
Expand All @@ -171,7 +181,7 @@ class ConfigCommand extends FlutterCommand {
if (configSetting == null) {
continue;
}
if (argResults?.wasParsed(configSetting) ?? false) {
if (argResults!.wasParsed(configSetting)) {
final bool keyValue = boolArg(configSetting);
globals.config.setValue(configSetting, keyValue);
globals.printStatus('Setting "$configSetting" value to "$keyValue".');
Expand Down Expand Up @@ -203,6 +213,10 @@ class ConfigCommand extends FlutterCommand {
if (results['android-sdk'] == null && androidSdk != null) {
results['android-sdk'] = androidSdk.directory.path;
}
final Java? java = globals.java;
if (results['jdk-dir'] == null && java != null) {
results['jdk-dir'] = java.javaHome;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is actually surprising to me, but I suppose we shouldn't break this.

}

globals.printStatus(const JsonEncoder.withIndent(' ').convert(results));
}
Expand Down
3 changes: 1 addition & 2 deletions packages/flutter_tools/lib/src/context_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,9 @@ Future<T> runInContext<T>(
platform: globals.platform,
userMessages: globals.userMessages,
processManager: globals.processManager,
androidStudio: globals.androidStudio,
java: globals.java,
androidSdk: globals.androidSdk,
logger: globals.logger,
fileSystem: globals.fs,
stdio: globals.stdio,
),
AndroidSdk: AndroidSdk.locateAndroidSdk,
Expand Down Expand Up @@ -255,6 +253,7 @@ Future<T> runInContext<T>(
platform: globals.platform,
),
Java: () => Java.find(
config: globals.config,
androidStudio: globals.androidStudio,
logger: globals.logger,
fileSystem: globals.fs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:convert';
import 'package:args/command_runner.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/java.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
Expand All @@ -18,9 +19,11 @@ import 'package:test/fake.dart';

import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/test_flutter_command_runner.dart';

void main() {
late Java fakeJava;
late FakeAndroidStudio fakeAndroidStudio;
late FakeAndroidSdk fakeAndroidSdk;
late FakeFlutterVersion fakeFlutterVersion;
Expand All @@ -31,6 +34,7 @@ void main() {
});

setUp(() {
fakeJava = FakeJava();
fakeAndroidStudio = FakeAndroidStudio();
fakeAndroidSdk = FakeAndroidSdk();
fakeFlutterVersion = FakeFlutterVersion();
Expand Down Expand Up @@ -65,16 +69,15 @@ void main() {
final dynamic jsonObject = json.decode(testLogger.statusText);
expect(jsonObject, const TypeMatcher<Map<String, dynamic>>());
if (jsonObject is Map<String, dynamic>) {
expect(jsonObject.containsKey('android-studio-dir'), true);
expect(jsonObject['android-studio-dir'], isNotNull);

expect(jsonObject.containsKey('android-sdk'), true);
expect(jsonObject['android-sdk'], isNotNull);
expect(jsonObject['android-studio-dir'], fakeAndroidStudio.directory);
expect(jsonObject['android-sdk'], fakeAndroidSdk.directory.path);
expect(jsonObject['jdk-dir'], fakeJava.javaHome);
}
verifyNoAnalytics();
}, overrides: <Type, Generator>{
AndroidStudio: () => fakeAndroidStudio,
AndroidSdk: () => fakeAndroidSdk,
Java: () => fakeJava,
Usage: () => testUsage,
});

Expand Down Expand Up @@ -289,7 +292,10 @@ void main() {

class FakeAndroidStudio extends Fake implements AndroidStudio, Comparable<AndroidStudio> {
@override
String get directory => 'path/to/android/stdio';
String get directory => 'path/to/android/studio';

@override
String? get javaPath => 'path/to/android/studio/jbr';
}

class FakeAndroidSdk extends Fake implements AndroidSdk {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/java.dart';
import 'package:flutter_tools/src/base/config.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:test/fake.dart';
Expand Down Expand Up @@ -345,99 +343,6 @@ void main() {
Platform: () => FakePlatform(operatingSystem: 'windows'),
Config: () => config,
});

group('findJavaBinary', () {
testUsingContext('returns the path of the JDK bundled with Android Studio, if it exists', () {
final String androidStudioBundledJdkHome = globals.androidStudio!.javaPath!;
final String expectedJavaBinaryPath = globals.fs.path.join(androidStudioBundledJdkHome, 'bin', 'java');

final String? foundJavaBinaryPath = Java.find(
logger: globals.logger,
androidStudio: globals.androidStudio,
fileSystem: globals.fs,
platform: globals.platform,
processManager: globals.processManager,
)?.binaryPath;

expect(foundJavaBinaryPath, expectedJavaBinaryPath);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
Platform: () => FakePlatform(),
Config: () => Config,
AndroidStudio: () => FakeAndroidStudioWithJdk(),
});

testUsingContext('returns the current value of JAVA_HOME if it is set and the JDK bundled with Android Studio could not be found', () {
final String expectedJavaBinaryPath = globals.fs.path.join('java-home-path', 'bin', 'java');

final String? foundJavaBinaryPath = Java.find(
logger: globals.logger,
androidStudio: globals.androidStudio,
fileSystem: globals.fs,
platform: globals.platform,
processManager: globals.processManager,
)?.binaryPath;

expect(foundJavaBinaryPath, expectedJavaBinaryPath);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.empty(),
Platform: () => FakePlatform(environment: <String, String>{
Java.javaHomeEnvironmentVariable: 'java-home-path',
}),
Config: () => Config,
AndroidStudio: () => FakeAndroidStudioWithoutJdk(),
});

testUsingContext('returns the java binary found on PATH if no other can be found', () {
final String? foundJavaBinaryPath = Java.find(
logger: globals.logger,
androidStudio: globals.androidStudio,
fileSystem: globals.fs,
platform: globals.platform,
processManager: globals.processManager,
)?.binaryPath;

expect(foundJavaBinaryPath, 'java');
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>['which', 'java'],
stdout: 'java',
),
]),
Platform: () => FakePlatform(),
Config: () => Config,
AndroidStudio: () => FakeAndroidStudioWithoutJdk(),
});

testUsingContext('returns null if no java binary could be found', () {
final String? foundJavaBinaryPath = Java.find(
logger: globals.logger,
androidStudio: globals.androidStudio,
fileSystem: globals.fs,
platform: globals.platform,
processManager: globals.processManager,
)?.binaryPath;

expect(foundJavaBinaryPath, null);
}, overrides: <Type, Generator>{
Logger: () => BufferLogger.test(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
const FakeCommand(
command: <String>['which', 'java'],
exitCode: 1,
),
]),
Platform: () => FakePlatform(),
Config: () => Config,
AndroidStudio: () => FakeAndroidStudioWithoutJdk(),
});
});
});
}

Expand Down
Loading