Commit 4d7c3c77 authored by Danny Tuppeny's avatar Danny Tuppeny Committed by Danny Tuppeny

Read information about AVDs from config.ini

parent 486e9534
...@@ -8,6 +8,7 @@ import 'package:meta/meta.dart'; ...@@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
import '../android/android_sdk.dart'; import '../android/android_sdk.dart';
import '../android/android_workflow.dart'; import '../android/android_workflow.dart';
import '../base/file_system.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../emulator.dart'; import '../emulator.dart';
import 'android_sdk.dart'; import 'android_sdk.dart';
...@@ -24,12 +25,19 @@ class AndroidEmulators extends EmulatorDiscovery { ...@@ -24,12 +25,19 @@ class AndroidEmulators extends EmulatorDiscovery {
} }
class AndroidEmulator extends Emulator { class AndroidEmulator extends Emulator {
AndroidEmulator( AndroidEmulator(String id, [this._properties])
String id : super(id, _properties != null && _properties.isNotEmpty);
) : super(id);
Map<String, String> _properties;
@override
String get name => _properties['hw.device.name'];
@override
String get manufacturer => _properties['hw.device.manufacturer'];
@override @override
String get name => id; String get label => _properties['avd.ini.displayname'];
// @override // @override
// Future<bool> launch() async { // Future<bool> launch() async {
...@@ -41,20 +49,57 @@ class AndroidEmulator extends Emulator { ...@@ -41,20 +49,57 @@ class AndroidEmulator extends Emulator {
/// Return the list of available emulator AVDs. /// Return the list of available emulator AVDs.
List<AndroidEmulator> getEmulatorAvds() { List<AndroidEmulator> getEmulatorAvds() {
final String emulatorPath = getEmulatorPath(androidSdk); final String emulatorPath = getEmulatorPath(androidSdk);
if (emulatorPath == null) if (emulatorPath == null) {
return <AndroidEmulator>[]; return <AndroidEmulator>[];
final String text = runSync(<String>[emulatorPath, '-list-avds']); }
final String listAvdsOutput = runSync(<String>[emulatorPath, '-list-avds']);
final List<AndroidEmulator> emulators = <AndroidEmulator>[]; final List<AndroidEmulator> emulators = <AndroidEmulator>[];
parseEmulatorAvdOutput(text, emulators); extractEmulatorAvdInfo(listAvdsOutput, emulators);
return emulators; return emulators;
} }
/// Parse the given `emulator -list-avds` output in [text], and fill out the given list /// Parse the given `emulator -list-avds` output in [text], and fill out the given list
/// of emulators. /// of emulators by reading information from the relevant ini files.
void extractEmulatorAvdInfo(String text, List<AndroidEmulator> emulators) {
for (String id in text.trim().split('\n')) {
emulators.add(_createEmulator(id));
}
}
AndroidEmulator _createEmulator(String id) {
id = id.trim();
final File iniFile = fs.file(fs.path.join(getAvdPath(), '$id.ini'));
final Map<String, String> ini = _parseIniLines(iniFile.readAsLinesSync());
if (ini['path'] != null) {
final File configFile = fs.file(fs.path.join(ini['path'], 'config.ini'));
if (configFile.existsSync()) {
final Map<String, String> properties = _parseIniLines(configFile.readAsLinesSync());
return new AndroidEmulator(id, properties);
}
}
return new AndroidEmulator(id);
}
// TODO: Tests
@visibleForTesting @visibleForTesting
void parseEmulatorAvdOutput(String text, Map<String, String> _parseIniLines(List<String> contents) {
List<AndroidEmulator> emulators) { final Map<String, String> results = <String, String>{};
for (String line in text.trim().split('\n')) {
emulators.add(new AndroidEmulator(line)); final Iterable<List<String>> properties = contents
.map((String l) => l.trim())
.where((String l) =>
l != '' && !l.startsWith('#')) // Strip blank lines/comments
.where((String l) =>
l.contains('=')) // Discard anything that isn't simple name=value
.map((String l) => l.split('=')); // Split into name/value
for (List<String> property in properties) {
results[property[0].trim()] = property[1].trim();
} }
return results;
} }
...@@ -59,9 +59,9 @@ String getAdbPath([AndroidSdk existingSdk]) { ...@@ -59,9 +59,9 @@ String getAdbPath([AndroidSdk existingSdk]) {
} }
} }
/// Locate ADB. Prefer to use one from an Android SDK, if we can locate that. /// Locate 'emulator'. Prefer to use one from an Android SDK, if we can locate that.
/// This should be used over accessing androidSdk.adbPath directly because it /// This should be used over accessing androidSdk.emulatorPath directly because it
/// will work for those users who have Android Platform Tools installed but /// will work for those users who have Android Tools installed but
/// not the full SDK. /// not the full SDK.
String getEmulatorPath([AndroidSdk existingSdk]) { String getEmulatorPath([AndroidSdk existingSdk]) {
if (existingSdk?.emulatorPath != null) if (existingSdk?.emulatorPath != null)
...@@ -76,6 +76,18 @@ String getEmulatorPath([AndroidSdk existingSdk]) { ...@@ -76,6 +76,18 @@ String getEmulatorPath([AndroidSdk existingSdk]) {
} }
} }
/// Locate the path for storing AVD emulator images. Returns null if none found.
String getAvdPath() {
final List<String> searchPaths = <String>[
platform.environment['ANDROID_AVD_HOME'],
fs.path.join(platform.environment['HOME'], '.android', 'avd'),
];
return searchPaths.where((String p) => p != null).firstWhere(
(String p) => fs.directory(p).existsSync(),
orElse: () => null,
);
}
class AndroidSdk { class AndroidSdk {
AndroidSdk(this.directory, [this.ndkDirectory, this.ndkCompiler, AndroidSdk(this.directory, [this.ndkDirectory, this.ndkCompiler,
this.ndkCompilerArgs]) { this.ndkCompilerArgs]) {
......
...@@ -43,7 +43,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow { ...@@ -43,7 +43,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
bool get canLaunchDevices => androidSdk != null && androidSdk.validateSdkWellFormed().isEmpty; bool get canLaunchDevices => androidSdk != null && androidSdk.validateSdkWellFormed().isEmpty;
@override @override
bool get canListEmulators => getEmulatorPath(androidSdk) != null; bool get canListEmulators => getEmulatorPath(androidSdk) != null && getAvdPath() != null;
static const String _kJdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/'; static const String _kJdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/';
......
...@@ -115,11 +115,13 @@ abstract class EmulatorDiscovery { ...@@ -115,11 +115,13 @@ abstract class EmulatorDiscovery {
} }
abstract class Emulator { abstract class Emulator {
Emulator(this.id); Emulator(this.id, this.hasConfig);
final String id; final String id;
final bool hasConfig;
String get name => id; String get name;
String get manufacturer;
String get label;
@override @override
int get hashCode => id.hashCode; int get hashCode => id.hashCode;
...@@ -145,6 +147,8 @@ abstract class Emulator { ...@@ -145,6 +147,8 @@ abstract class Emulator {
for (Emulator emulator in emulators) { for (Emulator emulator in emulators) {
table.add(<String>[ table.add(<String>[
emulator.name, emulator.name,
emulator.manufacturer,
emulator.label,
emulator.id, emulator.id,
]); ]);
} }
......
...@@ -19,9 +19,9 @@ void main() { ...@@ -19,9 +19,9 @@ void main() {
}); });
testUsingContext('getEmulatorsById', () async { testUsingContext('getEmulatorsById', () async {
final _MockEmulator emulator1 = new _MockEmulator('Nexus_5'); final _MockEmulator emulator1 = new _MockEmulator('Nexus_5', 'Nexus 5', 'Google', '');
final _MockEmulator emulator2 = new _MockEmulator('Nexus_5X_API_27_x86'); final _MockEmulator emulator2 = new _MockEmulator('Nexus_5X_API_27_x86', 'Nexus 5X', 'Google', '');
final _MockEmulator emulator3 = new _MockEmulator('iOS Simulator'); final _MockEmulator emulator3 = new _MockEmulator('iOS Simulator', 'iOS Simulator', 'Apple', '');
final List<Emulator> emulators = <Emulator>[emulator1, emulator2, emulator3]; final List<Emulator> emulators = <Emulator>[emulator1, emulator2, emulator3];
final EmulatorManager emulatorManager = new TestEmulatorManager(emulators); final EmulatorManager emulatorManager = new TestEmulatorManager(emulators);
...@@ -50,8 +50,15 @@ class TestEmulatorManager extends EmulatorManager { ...@@ -50,8 +50,15 @@ class TestEmulatorManager extends EmulatorManager {
} }
class _MockEmulator extends Emulator { class _MockEmulator extends Emulator {
_MockEmulator(String id) : super(id); _MockEmulator(String id, this.name, this.manufacturer, this.label) : super(id, true);
@override @override
void noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); final String name;
@override
final String manufacturer;
@override
final String label;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment