Read information about AVDs from config.ini
This commit is contained in:
committed by
Danny Tuppeny
parent
486e9534bf
commit
4d7c3c775f
@@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
|
||||
|
||||
import '../android/android_sdk.dart';
|
||||
import '../android/android_workflow.dart';
|
||||
import '../base/file_system.dart';
|
||||
import '../base/process.dart';
|
||||
import '../emulator.dart';
|
||||
import 'android_sdk.dart';
|
||||
@@ -24,12 +25,19 @@ class AndroidEmulators extends EmulatorDiscovery {
|
||||
}
|
||||
|
||||
class AndroidEmulator extends Emulator {
|
||||
AndroidEmulator(
|
||||
String id
|
||||
) : super(id);
|
||||
AndroidEmulator(String id, [this._properties])
|
||||
: super(id, _properties != null && _properties.isNotEmpty);
|
||||
|
||||
Map<String, String> _properties;
|
||||
|
||||
@override
|
||||
String get name => id;
|
||||
String get name => _properties['hw.device.name'];
|
||||
|
||||
@override
|
||||
String get manufacturer => _properties['hw.device.manufacturer'];
|
||||
|
||||
@override
|
||||
String get label => _properties['avd.ini.displayname'];
|
||||
|
||||
// @override
|
||||
// Future<bool> launch() async {
|
||||
@@ -41,20 +49,57 @@ class AndroidEmulator extends Emulator {
|
||||
/// Return the list of available emulator AVDs.
|
||||
List<AndroidEmulator> getEmulatorAvds() {
|
||||
final String emulatorPath = getEmulatorPath(androidSdk);
|
||||
if (emulatorPath == null)
|
||||
if (emulatorPath == null) {
|
||||
return <AndroidEmulator>[];
|
||||
final String text = runSync(<String>[emulatorPath, '-list-avds']);
|
||||
}
|
||||
|
||||
final String listAvdsOutput = runSync(<String>[emulatorPath, '-list-avds']);
|
||||
|
||||
final List<AndroidEmulator> emulators = <AndroidEmulator>[];
|
||||
parseEmulatorAvdOutput(text, emulators);
|
||||
extractEmulatorAvdInfo(listAvdsOutput, emulators);
|
||||
return emulators;
|
||||
}
|
||||
|
||||
/// Parse the given `emulator -list-avds` output in [text], and fill out the given list
|
||||
/// of emulators.
|
||||
@visibleForTesting
|
||||
void parseEmulatorAvdOutput(String text,
|
||||
List<AndroidEmulator> emulators) {
|
||||
for (String line in text.trim().split('\n')) {
|
||||
emulators.add(new AndroidEmulator(line));
|
||||
/// 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
|
||||
Map<String, String> _parseIniLines(List<String> contents) {
|
||||
final Map<String, String> results = <String, String>{};
|
||||
|
||||
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]) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate ADB. Prefer to use one from an Android SDK, if we can locate that.
|
||||
/// This should be used over accessing androidSdk.adbPath directly because it
|
||||
/// will work for those users who have Android Platform Tools installed but
|
||||
/// Locate 'emulator'. Prefer to use one from an Android SDK, if we can locate that.
|
||||
/// This should be used over accessing androidSdk.emulatorPath directly because it
|
||||
/// will work for those users who have Android Tools installed but
|
||||
/// not the full SDK.
|
||||
String getEmulatorPath([AndroidSdk existingSdk]) {
|
||||
if (existingSdk?.emulatorPath != null)
|
||||
@@ -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 {
|
||||
AndroidSdk(this.directory, [this.ndkDirectory, this.ndkCompiler,
|
||||
this.ndkCompilerArgs]) {
|
||||
|
||||
@@ -43,7 +43,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
|
||||
bool get canLaunchDevices => androidSdk != null && androidSdk.validateSdkWellFormed().isEmpty;
|
||||
|
||||
@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/';
|
||||
|
||||
|
||||
@@ -115,11 +115,13 @@ abstract class EmulatorDiscovery {
|
||||
}
|
||||
|
||||
abstract class Emulator {
|
||||
Emulator(this.id);
|
||||
Emulator(this.id, this.hasConfig);
|
||||
|
||||
final String id;
|
||||
|
||||
String get name => id;
|
||||
final bool hasConfig;
|
||||
String get name;
|
||||
String get manufacturer;
|
||||
String get label;
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode;
|
||||
@@ -145,6 +147,8 @@ abstract class Emulator {
|
||||
for (Emulator emulator in emulators) {
|
||||
table.add(<String>[
|
||||
emulator.name,
|
||||
emulator.manufacturer,
|
||||
emulator.label,
|
||||
emulator.id,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ void main() {
|
||||
});
|
||||
|
||||
testUsingContext('getEmulatorsById', () async {
|
||||
final _MockEmulator emulator1 = new _MockEmulator('Nexus_5');
|
||||
final _MockEmulator emulator2 = new _MockEmulator('Nexus_5X_API_27_x86');
|
||||
final _MockEmulator emulator3 = new _MockEmulator('iOS Simulator');
|
||||
final _MockEmulator emulator1 = new _MockEmulator('Nexus_5', 'Nexus 5', 'Google', '');
|
||||
final _MockEmulator emulator2 = new _MockEmulator('Nexus_5X_API_27_x86', 'Nexus 5X', 'Google', '');
|
||||
final _MockEmulator emulator3 = new _MockEmulator('iOS Simulator', 'iOS Simulator', 'Apple', '');
|
||||
final List<Emulator> emulators = <Emulator>[emulator1, emulator2, emulator3];
|
||||
final EmulatorManager emulatorManager = new TestEmulatorManager(emulators);
|
||||
|
||||
@@ -50,8 +50,15 @@ class TestEmulatorManager extends EmulatorManager {
|
||||
}
|
||||
|
||||
class _MockEmulator extends Emulator {
|
||||
_MockEmulator(String id) : super(id);
|
||||
_MockEmulator(String id, this.name, this.manufacturer, this.label) : super(id, true);
|
||||
|
||||
@override
|
||||
void noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
final String name;
|
||||
|
||||
@override
|
||||
final String manufacturer;
|
||||
|
||||
@override
|
||||
final String label;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user