Migrate android_device to null safety (#92128)
This commit is contained in:
parent
53e04de681
commit
0c9a420583
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
@ -60,13 +58,13 @@ class AndroidDevice extends Device {
|
|||||||
AndroidDevice(
|
AndroidDevice(
|
||||||
String id, {
|
String id, {
|
||||||
this.productID,
|
this.productID,
|
||||||
this.modelID,
|
required this.modelID,
|
||||||
this.deviceCodeName,
|
this.deviceCodeName,
|
||||||
@required Logger logger,
|
required Logger logger,
|
||||||
@required ProcessManager processManager,
|
required ProcessManager processManager,
|
||||||
@required Platform platform,
|
required Platform platform,
|
||||||
@required AndroidSdk androidSdk,
|
required AndroidSdk androidSdk,
|
||||||
@required FileSystem fileSystem,
|
required FileSystem fileSystem,
|
||||||
AndroidConsoleSocketFactory androidConsoleSocketFactory = kAndroidConsoleSocketFactory,
|
AndroidConsoleSocketFactory androidConsoleSocketFactory = kAndroidConsoleSocketFactory,
|
||||||
}) : _logger = logger,
|
}) : _logger = logger,
|
||||||
_processManager = processManager,
|
_processManager = processManager,
|
||||||
@ -90,17 +88,12 @@ class AndroidDevice extends Device {
|
|||||||
final ProcessUtils _processUtils;
|
final ProcessUtils _processUtils;
|
||||||
final AndroidConsoleSocketFactory _androidConsoleSocketFactory;
|
final AndroidConsoleSocketFactory _androidConsoleSocketFactory;
|
||||||
|
|
||||||
final String productID;
|
final String? productID;
|
||||||
final String modelID;
|
final String modelID;
|
||||||
final String deviceCodeName;
|
final String? deviceCodeName;
|
||||||
|
|
||||||
Map<String, String> _properties;
|
late final Future<Map<String, String>> _properties = () async {
|
||||||
bool _isLocalEmulator;
|
Map<String, String> properties = <String, String>{};
|
||||||
TargetPlatform _applicationPlatform;
|
|
||||||
|
|
||||||
Future<String> _getProperty(String name) async {
|
|
||||||
if (_properties == null) {
|
|
||||||
_properties = <String, String>{};
|
|
||||||
|
|
||||||
final List<String> propCommand = adbCommandForDevice(<String>['shell', 'getprop']);
|
final List<String> propCommand = adbCommandForDevice(<String>['shell', 'getprop']);
|
||||||
_logger.printTrace(propCommand.join(' '));
|
_logger.printTrace(propCommand.join(' '));
|
||||||
@ -114,7 +107,7 @@ class AndroidDevice extends Device {
|
|||||||
stderrEncoding: latin1,
|
stderrEncoding: latin1,
|
||||||
);
|
);
|
||||||
if (result.exitCode == 0 || _allowHeapCorruptionOnWindows(result.exitCode, _platform)) {
|
if (result.exitCode == 0 || _allowHeapCorruptionOnWindows(result.exitCode, _platform)) {
|
||||||
_properties = parseAdbDeviceProperties(result.stdout as String);
|
properties = parseAdbDeviceProperties(result.stdout as String);
|
||||||
} else {
|
} else {
|
||||||
_logger.printError('Error ${result.exitCode} retrieving device properties for $name:');
|
_logger.printError('Error ${result.exitCode} retrieving device properties for $name:');
|
||||||
_logger.printError(result.stderr as String);
|
_logger.printError(result.stderr as String);
|
||||||
@ -122,28 +115,26 @@ class AndroidDevice extends Device {
|
|||||||
} on ProcessException catch (error) {
|
} on ProcessException catch (error) {
|
||||||
_logger.printError('Error retrieving device properties for $name: $error');
|
_logger.printError('Error retrieving device properties for $name: $error');
|
||||||
}
|
}
|
||||||
}
|
return properties;
|
||||||
|
}();
|
||||||
|
|
||||||
return _properties[name];
|
Future<String?> _getProperty(String name) async {
|
||||||
|
return (await _properties)[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> get isLocalEmulator async {
|
late final Future<bool> isLocalEmulator = () async {
|
||||||
if (_isLocalEmulator == null) {
|
final String? hardware = await _getProperty('ro.hardware');
|
||||||
final String hardware = await _getProperty('ro.hardware');
|
|
||||||
_logger.printTrace('ro.hardware = $hardware');
|
_logger.printTrace('ro.hardware = $hardware');
|
||||||
if (kKnownHardware.containsKey(hardware)) {
|
if (kKnownHardware.containsKey(hardware)) {
|
||||||
// Look for known hardware models.
|
// Look for known hardware models.
|
||||||
_isLocalEmulator = kKnownHardware[hardware] == HardwareType.emulator;
|
return kKnownHardware[hardware] == HardwareType.emulator;
|
||||||
} else {
|
}
|
||||||
// Fall back to a best-effort heuristic-based approach.
|
// Fall back to a best-effort heuristic-based approach.
|
||||||
final String characteristics = await _getProperty('ro.build.characteristics');
|
final String? characteristics = await _getProperty('ro.build.characteristics');
|
||||||
_logger.printTrace('ro.build.characteristics = $characteristics');
|
_logger.printTrace('ro.build.characteristics = $characteristics');
|
||||||
_isLocalEmulator = characteristics != null && characteristics.contains('emulator');
|
return characteristics != null && characteristics.contains('emulator');
|
||||||
}
|
}();
|
||||||
}
|
|
||||||
return _isLocalEmulator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The unique identifier for the emulator that corresponds to this device, or
|
/// The unique identifier for the emulator that corresponds to this device, or
|
||||||
/// null if it is not an emulator.
|
/// null if it is not an emulator.
|
||||||
@ -152,7 +143,7 @@ class AndroidDevice extends Device {
|
|||||||
/// this name may require connecting to the device and if an error occurs null
|
/// this name may require connecting to the device and if an error occurs null
|
||||||
/// will be returned.
|
/// will be returned.
|
||||||
@override
|
@override
|
||||||
Future<String> get emulatorId async {
|
Future<String?> get emulatorId async {
|
||||||
if (!(await isLocalEmulator)) {
|
if (!(await isLocalEmulator)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -161,13 +152,13 @@ class AndroidDevice extends Device {
|
|||||||
// Android Console port number.
|
// Android Console port number.
|
||||||
final RegExp emulatorPortRegex = RegExp(r'emulator-(\d+)');
|
final RegExp emulatorPortRegex = RegExp(r'emulator-(\d+)');
|
||||||
|
|
||||||
final Match portMatch = emulatorPortRegex.firstMatch(id);
|
final Match? portMatch = emulatorPortRegex.firstMatch(id);
|
||||||
if (portMatch == null || portMatch.groupCount < 1) {
|
if (portMatch == null || portMatch.groupCount < 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String host = 'localhost';
|
const String host = 'localhost';
|
||||||
final int port = int.parse(portMatch.group(1));
|
final int port = int.parse(portMatch.group(1)!);
|
||||||
_logger.printTrace('Fetching avd name for $name via Android console on $host:$port');
|
_logger.printTrace('Fetching avd name for $name via Android console on $host:$port');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -196,8 +187,7 @@ class AndroidDevice extends Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<TargetPlatform> get targetPlatform async {
|
late final Future<TargetPlatform> targetPlatform = () async {
|
||||||
if (_applicationPlatform == null) {
|
|
||||||
// http://developer.android.com/ndk/guides/abis.html (x86, armeabi-v7a, ...)
|
// http://developer.android.com/ndk/guides/abis.html (x86, armeabi-v7a, ...)
|
||||||
switch (await _getProperty('ro.product.cpu.abi')) {
|
switch (await _getProperty('ro.product.cpu.abi')) {
|
||||||
case 'arm64-v8a':
|
case 'arm64-v8a':
|
||||||
@ -205,27 +195,20 @@ class AndroidDevice extends Device {
|
|||||||
// like the Kindle Fire 8, misreport the abilist. We might not
|
// like the Kindle Fire 8, misreport the abilist. We might not
|
||||||
// be able to retrieve this property, in which case we fall back
|
// be able to retrieve this property, in which case we fall back
|
||||||
// to assuming 64 bit.
|
// to assuming 64 bit.
|
||||||
final String abilist = await _getProperty('ro.product.cpu.abilist');
|
final String? abilist = await _getProperty('ro.product.cpu.abilist');
|
||||||
if (abilist == null || abilist.contains('arm64-v8a')) {
|
if (abilist == null || abilist.contains('arm64-v8a')) {
|
||||||
_applicationPlatform = TargetPlatform.android_arm64;
|
return TargetPlatform.android_arm64;
|
||||||
} else {
|
} else {
|
||||||
_applicationPlatform = TargetPlatform.android_arm;
|
return TargetPlatform.android_arm;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 'x86_64':
|
case 'x86_64':
|
||||||
_applicationPlatform = TargetPlatform.android_x64;
|
return TargetPlatform.android_x64;
|
||||||
break;
|
|
||||||
case 'x86':
|
case 'x86':
|
||||||
_applicationPlatform = TargetPlatform.android_x86;
|
return TargetPlatform.android_x86;
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
_applicationPlatform = TargetPlatform.android_arm;
|
return TargetPlatform.android_arm;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _applicationPlatform;
|
|
||||||
}
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> supportsRuntimeMode(BuildMode buildMode) async {
|
Future<bool> supportsRuntimeMode(BuildMode buildMode) async {
|
||||||
@ -249,28 +232,27 @@ class AndroidDevice extends Device {
|
|||||||
case TargetPlatform.windows_x64:
|
case TargetPlatform.windows_x64:
|
||||||
throw UnsupportedError('Invalid target platform for Android');
|
throw UnsupportedError('Invalid target platform for Android');
|
||||||
}
|
}
|
||||||
throw null; // dead code, remove after null migration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> get sdkNameAndVersion async => 'Android ${await _sdkVersion} (API ${await apiVersion})';
|
Future<String> get sdkNameAndVersion async => 'Android ${await _sdkVersion} (API ${await apiVersion})';
|
||||||
|
|
||||||
Future<String> get _sdkVersion => _getProperty('ro.build.version.release');
|
Future<String?> get _sdkVersion => _getProperty('ro.build.version.release');
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
Future<String> get apiVersion => _getProperty('ro.build.version.sdk');
|
Future<String?> get apiVersion => _getProperty('ro.build.version.sdk');
|
||||||
|
|
||||||
AdbLogReader _logReader;
|
AdbLogReader? _logReader;
|
||||||
AdbLogReader _pastLogReader;
|
AdbLogReader? _pastLogReader;
|
||||||
AndroidDevicePortForwarder _portForwarder;
|
AndroidDevicePortForwarder? _portForwarder;
|
||||||
|
|
||||||
List<String> adbCommandForDevice(List<String> args) {
|
List<String> adbCommandForDevice(List<String> args) {
|
||||||
return <String>[_androidSdk.adbPath, '-s', id, ...args];
|
return <String>[_androidSdk.adbPath!, '-s', id, ...args];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<RunResult> runAdbCheckedAsync(
|
Future<RunResult> runAdbCheckedAsync(
|
||||||
List<String> params, {
|
List<String> params, {
|
||||||
String workingDirectory,
|
String? workingDirectory,
|
||||||
bool allowReentrantFlutter = false,
|
bool allowReentrantFlutter = false,
|
||||||
}) async {
|
}) async {
|
||||||
return _processUtils.run(
|
return _processUtils.run(
|
||||||
@ -284,11 +266,11 @@ class AndroidDevice extends Device {
|
|||||||
|
|
||||||
bool _isValidAdbVersion(String adbVersion) {
|
bool _isValidAdbVersion(String adbVersion) {
|
||||||
// Sample output: 'Android Debug Bridge version 1.0.31'
|
// Sample output: 'Android Debug Bridge version 1.0.31'
|
||||||
final Match versionFields = RegExp(r'(\d+)\.(\d+)\.(\d+)').firstMatch(adbVersion);
|
final Match? versionFields = RegExp(r'(\d+)\.(\d+)\.(\d+)').firstMatch(adbVersion);
|
||||||
if (versionFields != null) {
|
if (versionFields != null) {
|
||||||
final int majorVersion = int.parse(versionFields[1]);
|
final int majorVersion = int.parse(versionFields[1]!);
|
||||||
final int minorVersion = int.parse(versionFields[2]);
|
final int minorVersion = int.parse(versionFields[2]!);
|
||||||
final int patchVersion = int.parse(versionFields[3]);
|
final int patchVersion = int.parse(versionFields[3]!);
|
||||||
if (majorVersion > 1) {
|
if (majorVersion > 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -306,19 +288,20 @@ class AndroidDevice extends Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _checkForSupportedAdbVersion() async {
|
Future<bool> _checkForSupportedAdbVersion() async {
|
||||||
if (_androidSdk == null) {
|
final String? adbPath = _androidSdk.adbPath;
|
||||||
|
if (adbPath == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final RunResult adbVersion = await _processUtils.run(
|
final RunResult adbVersion = await _processUtils.run(
|
||||||
<String>[_androidSdk.adbPath, 'version'],
|
<String>[adbPath, 'version'],
|
||||||
throwOnError: true,
|
throwOnError: true,
|
||||||
);
|
);
|
||||||
if (_isValidAdbVersion(adbVersion.stdout)) {
|
if (_isValidAdbVersion(adbVersion.stdout)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
_logger.printError('The ADB at "${_androidSdk.adbPath}" is too old; please install version 1.0.39 or later.');
|
_logger.printError('The ADB at "$adbPath" is too old; please install version 1.0.39 or later.');
|
||||||
} on Exception catch (error, trace) {
|
} on Exception catch (error, trace) {
|
||||||
_logger.printError('Error running ADB: $error', stackTrace: trace);
|
_logger.printError('Error running ADB: $error', stackTrace: trace);
|
||||||
}
|
}
|
||||||
@ -327,13 +310,17 @@ class AndroidDevice extends Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _checkForSupportedAndroidVersion() async {
|
Future<bool> _checkForSupportedAndroidVersion() async {
|
||||||
|
final String? adbPath = _androidSdk.adbPath;
|
||||||
|
if (adbPath == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// If the server is automatically restarted, then we get irrelevant
|
// If the server is automatically restarted, then we get irrelevant
|
||||||
// output lines like this, which we want to ignore:
|
// output lines like this, which we want to ignore:
|
||||||
// adb server is out of date. killing..
|
// adb server is out of date. killing..
|
||||||
// * daemon started successfully *
|
// * daemon started successfully *
|
||||||
await _processUtils.run(
|
await _processUtils.run(
|
||||||
<String>[_androidSdk.adbPath, 'start-server'],
|
<String>[adbPath, 'start-server'],
|
||||||
throwOnError: true,
|
throwOnError: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -343,7 +330,7 @@ class AndroidDevice extends Device {
|
|||||||
final String sdkVersion = await _getProperty('ro.build.version.sdk')
|
final String sdkVersion = await _getProperty('ro.build.version.sdk')
|
||||||
?? minApiLevel.toString();
|
?? minApiLevel.toString();
|
||||||
|
|
||||||
final int sdkVersionParsed = int.tryParse(sdkVersion);
|
final int? sdkVersionParsed = int.tryParse(sdkVersion);
|
||||||
if (sdkVersionParsed == null) {
|
if (sdkVersionParsed == null) {
|
||||||
_logger.printError('Unexpected response from getprop: "$sdkVersion"');
|
_logger.printError('Unexpected response from getprop: "$sdkVersion"');
|
||||||
return false;
|
return false;
|
||||||
@ -385,7 +372,7 @@ class AndroidDevice extends Device {
|
|||||||
@override
|
@override
|
||||||
Future<bool> isAppInstalled(
|
Future<bool> isAppInstalled(
|
||||||
AndroidApk app, {
|
AndroidApk app, {
|
||||||
String userIdentifier,
|
String? userIdentifier,
|
||||||
}) async {
|
}) async {
|
||||||
// This call takes 400ms - 600ms.
|
// This call takes 400ms - 600ms.
|
||||||
try {
|
try {
|
||||||
@ -414,9 +401,9 @@ class AndroidDevice extends Device {
|
|||||||
@override
|
@override
|
||||||
Future<bool> installApp(
|
Future<bool> installApp(
|
||||||
AndroidApk app, {
|
AndroidApk app, {
|
||||||
String userIdentifier,
|
String? userIdentifier,
|
||||||
}) async {
|
}) async {
|
||||||
if (!await _isAdbValid()) {
|
if (!await _adbIsValid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final bool wasInstalled = await isAppInstalled(app, userIdentifier: userIdentifier);
|
final bool wasInstalled = await isAppInstalled(app, userIdentifier: userIdentifier);
|
||||||
@ -446,7 +433,7 @@ class AndroidDevice extends Device {
|
|||||||
|
|
||||||
Future<bool> _installApp(
|
Future<bool> _installApp(
|
||||||
AndroidApk app, {
|
AndroidApk app, {
|
||||||
String userIdentifier,
|
String? userIdentifier,
|
||||||
}) async {
|
}) async {
|
||||||
if (!app.file.existsSync()) {
|
if (!app.file.existsSync()) {
|
||||||
_logger.printError('"${_fileSystem.path.relative(app.file.path)}" does not exist.');
|
_logger.printError('"${_fileSystem.path.relative(app.file.path)}" does not exist.');
|
||||||
@ -469,7 +456,7 @@ class AndroidDevice extends Device {
|
|||||||
// Some versions of adb exit with exit code 0 even on failure :(
|
// Some versions of adb exit with exit code 0 even on failure :(
|
||||||
// Parsing the output to check for failures.
|
// Parsing the output to check for failures.
|
||||||
final RegExp failureExp = RegExp(r'^Failure.*$', multiLine: true);
|
final RegExp failureExp = RegExp(r'^Failure.*$', multiLine: true);
|
||||||
final String failure = failureExp.stringMatch(installResult.stdout);
|
final String? failure = failureExp.stringMatch(installResult.stdout);
|
||||||
if (failure != null) {
|
if (failure != null) {
|
||||||
_logger.printError('Package install error: $failure');
|
_logger.printError('Package install error: $failure');
|
||||||
return false;
|
return false;
|
||||||
@ -497,9 +484,9 @@ class AndroidDevice extends Device {
|
|||||||
@override
|
@override
|
||||||
Future<bool> uninstallApp(
|
Future<bool> uninstallApp(
|
||||||
AndroidApk app, {
|
AndroidApk app, {
|
||||||
String userIdentifier,
|
String? userIdentifier,
|
||||||
}) async {
|
}) async {
|
||||||
if (!await _isAdbValid()) {
|
if (!await _adbIsValid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,7 +506,7 @@ class AndroidDevice extends Device {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final RegExp failureExp = RegExp(r'^Failure.*$', multiLine: true);
|
final RegExp failureExp = RegExp(r'^Failure.*$', multiLine: true);
|
||||||
final String failure = failureExp.stringMatch(uninstallOut);
|
final String? failure = failureExp.stringMatch(uninstallOut);
|
||||||
if (failure != null) {
|
if (failure != null) {
|
||||||
_logger.printError('Package uninstall error: $failure');
|
_logger.printError('Package uninstall error: $failure');
|
||||||
return false;
|
return false;
|
||||||
@ -528,25 +515,24 @@ class AndroidDevice extends Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Whether the adb and Android versions are aligned.
|
// Whether the adb and Android versions are aligned.
|
||||||
bool _adbIsValid;
|
late final Future<bool> _adbIsValid = () async {
|
||||||
Future<bool> _isAdbValid() async {
|
return await _checkForSupportedAdbVersion() && await _checkForSupportedAndroidVersion();
|
||||||
return _adbIsValid ??= await _checkForSupportedAdbVersion() && await _checkForSupportedAndroidVersion();
|
}();
|
||||||
}
|
|
||||||
|
|
||||||
AndroidApk _package;
|
AndroidApk? _package;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<LaunchResult> startApp(
|
Future<LaunchResult> startApp(
|
||||||
AndroidApk package, {
|
AndroidApk package, {
|
||||||
String mainPath,
|
String? mainPath,
|
||||||
String route,
|
String? route,
|
||||||
DebuggingOptions debuggingOptions,
|
required DebuggingOptions debuggingOptions,
|
||||||
Map<String, dynamic> platformArgs = const <String, Object>{},
|
Map<String, Object?> platformArgs = const <String, Object>{},
|
||||||
bool prebuiltApplication = false,
|
bool prebuiltApplication = false,
|
||||||
bool ipv6 = false,
|
bool ipv6 = false,
|
||||||
String userIdentifier,
|
String? userIdentifier,
|
||||||
}) async {
|
}) async {
|
||||||
if (!await _isAdbValid()) {
|
if (!await _adbIsValid) {
|
||||||
return LaunchResult.failed();
|
return LaunchResult.failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,19 +575,19 @@ class AndroidDevice extends Device {
|
|||||||
if (!prebuiltApplication || _androidSdk.licensesAvailable && _androidSdk.latestVersion == null) {
|
if (!prebuiltApplication || _androidSdk.licensesAvailable && _androidSdk.latestVersion == null) {
|
||||||
_logger.printTrace('Building APK');
|
_logger.printTrace('Building APK');
|
||||||
final FlutterProject project = FlutterProject.current();
|
final FlutterProject project = FlutterProject.current();
|
||||||
await androidBuilder.buildApk(
|
await androidBuilder!.buildApk(
|
||||||
project: project,
|
project: project,
|
||||||
target: mainPath,
|
target: mainPath ?? 'lib/main.dart',
|
||||||
androidBuildInfo: AndroidBuildInfo(
|
androidBuildInfo: AndroidBuildInfo(
|
||||||
debuggingOptions.buildInfo,
|
debuggingOptions.buildInfo,
|
||||||
targetArchs: <AndroidArch>[androidArch],
|
targetArchs: <AndroidArch>[androidArch],
|
||||||
fastStart: debuggingOptions.fastStart,
|
fastStart: debuggingOptions.fastStart,
|
||||||
multidexEnabled: (platformArgs['multidex'] as bool) ?? false,
|
multidexEnabled: (platformArgs['multidex'] as bool?) ?? false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
// Package has been built, so we can get the updated application ID and
|
// Package has been built, so we can get the updated application ID and
|
||||||
// activity name from the .apk.
|
// activity name from the .apk.
|
||||||
package = await ApplicationPackageFactory.instance
|
package = await ApplicationPackageFactory.instance!
|
||||||
.getPackageForPlatform(devicePlatform, buildInfo: debuggingOptions.buildInfo) as AndroidApk;
|
.getPackageForPlatform(devicePlatform, buildInfo: debuggingOptions.buildInfo) as AndroidApk;
|
||||||
}
|
}
|
||||||
// There was a failure parsing the android project information.
|
// There was a failure parsing the android project information.
|
||||||
@ -616,8 +602,8 @@ class AndroidDevice extends Device {
|
|||||||
return LaunchResult.failed();
|
return LaunchResult.failed();
|
||||||
}
|
}
|
||||||
|
|
||||||
final bool traceStartup = platformArgs['trace-startup'] as bool ?? false;
|
final bool traceStartup = platformArgs['trace-startup'] as bool? ?? false;
|
||||||
ProtocolDiscovery observatoryDiscovery;
|
ProtocolDiscovery? observatoryDiscovery;
|
||||||
|
|
||||||
if (debuggingOptions.debuggingEnabled) {
|
if (debuggingOptions.debuggingEnabled) {
|
||||||
observatoryDiscovery = ProtocolDiscovery.observatory(
|
observatoryDiscovery = ProtocolDiscovery.observatory(
|
||||||
@ -637,6 +623,8 @@ class AndroidDevice extends Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
|
final String dartVmFlags = computeDartVmFlags(debuggingOptions);
|
||||||
|
final String? traceAllowlist = debuggingOptions.traceAllowlist;
|
||||||
|
final String? traceSkiaAllowlist = debuggingOptions.traceSkiaAllowlist;
|
||||||
final List<String> cmd = <String>[
|
final List<String> cmd = <String>[
|
||||||
'shell', 'am', 'start',
|
'shell', 'am', 'start',
|
||||||
'-a', 'android.intent.action.RUN',
|
'-a', 'android.intent.action.RUN',
|
||||||
@ -653,10 +641,10 @@ class AndroidDevice extends Device {
|
|||||||
...<String>['--ez', 'skia-deterministic-rendering', 'true'],
|
...<String>['--ez', 'skia-deterministic-rendering', 'true'],
|
||||||
if (debuggingOptions.traceSkia)
|
if (debuggingOptions.traceSkia)
|
||||||
...<String>['--ez', 'trace-skia', 'true'],
|
...<String>['--ez', 'trace-skia', 'true'],
|
||||||
if (debuggingOptions.traceAllowlist != null)
|
if (traceAllowlist != null)
|
||||||
...<String>['--es', 'trace-allowlist', debuggingOptions.traceAllowlist],
|
...<String>['--es', 'trace-allowlist', traceAllowlist],
|
||||||
if (debuggingOptions.traceSkiaAllowlist != null)
|
if (traceSkiaAllowlist != null)
|
||||||
...<String>['--es', 'trace-skia-allowlist', debuggingOptions.traceSkiaAllowlist],
|
...<String>['--es', 'trace-skia-allowlist', traceSkiaAllowlist],
|
||||||
if (debuggingOptions.traceSystrace)
|
if (debuggingOptions.traceSystrace)
|
||||||
...<String>['--ez', 'trace-systrace', 'true'],
|
...<String>['--ez', 'trace-systrace', 'true'],
|
||||||
if (debuggingOptions.endlessTraceBuffer)
|
if (debuggingOptions.endlessTraceBuffer)
|
||||||
@ -703,9 +691,9 @@ class AndroidDevice extends Device {
|
|||||||
// device has printed "Observatory is listening on...".
|
// device has printed "Observatory is listening on...".
|
||||||
_logger.printTrace('Waiting for observatory port to be available...');
|
_logger.printTrace('Waiting for observatory port to be available...');
|
||||||
try {
|
try {
|
||||||
Uri observatoryUri;
|
Uri? observatoryUri;
|
||||||
if (debuggingOptions.buildInfo.isDebug || debuggingOptions.buildInfo.isProfile) {
|
if (debuggingOptions.buildInfo.isDebug || debuggingOptions.buildInfo.isProfile) {
|
||||||
observatoryUri = await observatoryDiscovery.uri;
|
observatoryUri = await observatoryDiscovery?.uri;
|
||||||
if (observatoryUri == null) {
|
if (observatoryUri == null) {
|
||||||
_logger.printError(
|
_logger.printError(
|
||||||
'Error waiting for a debug connection: '
|
'Error waiting for a debug connection: '
|
||||||
@ -719,7 +707,7 @@ class AndroidDevice extends Device {
|
|||||||
_logger.printError('Error waiting for a debug connection: $error');
|
_logger.printError('Error waiting for a debug connection: $error');
|
||||||
return LaunchResult.failed();
|
return LaunchResult.failed();
|
||||||
} finally {
|
} finally {
|
||||||
await observatoryDiscovery.cancel();
|
await observatoryDiscovery?.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,7 +723,7 @@ class AndroidDevice extends Device {
|
|||||||
@override
|
@override
|
||||||
Future<bool> stopApp(
|
Future<bool> stopApp(
|
||||||
AndroidApk app, {
|
AndroidApk app, {
|
||||||
String userIdentifier,
|
String? userIdentifier,
|
||||||
}) {
|
}) {
|
||||||
if (app == null) {
|
if (app == null) {
|
||||||
return Future<bool>.value(false);
|
return Future<bool>.value(false);
|
||||||
@ -754,11 +742,16 @@ class AndroidDevice extends Device {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<MemoryInfo> queryMemoryInfo() async {
|
Future<MemoryInfo> queryMemoryInfo() async {
|
||||||
|
final AndroidApk? package = _package;
|
||||||
|
if (package == null) {
|
||||||
|
_logger.printError('Android package unknown, skipping dumpsys meminfo.');
|
||||||
|
return const MemoryInfo.empty();
|
||||||
|
}
|
||||||
final RunResult runResult = await _processUtils.run(adbCommandForDevice(<String>[
|
final RunResult runResult = await _processUtils.run(adbCommandForDevice(<String>[
|
||||||
'shell',
|
'shell',
|
||||||
'dumpsys',
|
'dumpsys',
|
||||||
'meminfo',
|
'meminfo',
|
||||||
_package.id,
|
package.id,
|
||||||
'-d',
|
'-d',
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@ -775,7 +768,7 @@ class AndroidDevice extends Device {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<DeviceLogReader> getLogReader({
|
FutureOr<DeviceLogReader> getLogReader({
|
||||||
AndroidApk app,
|
AndroidApk? app,
|
||||||
bool includePastLogs = false,
|
bool includePastLogs = false,
|
||||||
}) async {
|
}) async {
|
||||||
// The Android log reader isn't app-specific. The `app` parameter isn't used.
|
// The Android log reader isn't app-specific. The `app` parameter isn't used.
|
||||||
@ -794,19 +787,25 @@ class AndroidDevice extends Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DevicePortForwarder get portForwarder => _portForwarder ??= AndroidDevicePortForwarder(
|
late final DevicePortForwarder? portForwarder = () {
|
||||||
|
final String? adbPath = _androidSdk.adbPath;
|
||||||
|
if (adbPath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return AndroidDevicePortForwarder(
|
||||||
processManager: _processManager,
|
processManager: _processManager,
|
||||||
logger: _logger,
|
logger: _logger,
|
||||||
deviceId: id,
|
deviceId: id,
|
||||||
adbPath: _androidSdk.adbPath,
|
adbPath: adbPath,
|
||||||
);
|
);
|
||||||
|
}();
|
||||||
|
|
||||||
static final RegExp _timeRegExp = RegExp(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}', multiLine: true);
|
static final RegExp _timeRegExp = RegExp(r'^\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}', multiLine: true);
|
||||||
|
|
||||||
/// Return the most recent timestamp in the Android log or [null] if there is
|
/// Return the most recent timestamp in the Android log or [null] if there is
|
||||||
/// no available timestamp. The format can be passed to logcat's -T option.
|
/// no available timestamp. The format can be passed to logcat's -T option.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
Future<String> lastLogcatTimestamp() async {
|
Future<String?> lastLogcatTimestamp() async {
|
||||||
RunResult output;
|
RunResult output;
|
||||||
try {
|
try {
|
||||||
output = await runAdbCheckedAsync(<String>[
|
output = await runAdbCheckedAsync(<String>[
|
||||||
@ -816,7 +815,7 @@ class AndroidDevice extends Device {
|
|||||||
_logger.printError('Failed to extract the most recent timestamp from the Android log: $error.');
|
_logger.printError('Failed to extract the most recent timestamp from the Android log: $error.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final Match timeMatch = _timeRegExp.firstMatch(output.stdout);
|
final Match? timeMatch = _timeRegExp.firstMatch(output.stdout);
|
||||||
return timeMatch?.group(0);
|
return timeMatch?.group(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -854,7 +853,7 @@ Map<String, String> parseAdbDeviceProperties(String str) {
|
|||||||
final Map<String, String> properties = <String, String>{};
|
final Map<String, String> properties = <String, String>{};
|
||||||
final RegExp propertyExp = RegExp(r'\[(.*?)\]: \[(.*?)\]');
|
final RegExp propertyExp = RegExp(r'\[(.*?)\]: \[(.*?)\]');
|
||||||
for (final Match match in propertyExp.allMatches(str)) {
|
for (final Match match in propertyExp.allMatches(str)) {
|
||||||
properties[match.group(1)] = match.group(2);
|
properties[match.group(1)!] = match.group(2)!;
|
||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
@ -1011,12 +1010,7 @@ class AndroidMemoryInfo extends MemoryInfo {
|
|||||||
|
|
||||||
/// A log reader that logs from `adb logcat`.
|
/// A log reader that logs from `adb logcat`.
|
||||||
class AdbLogReader extends DeviceLogReader {
|
class AdbLogReader extends DeviceLogReader {
|
||||||
AdbLogReader._(this._adbProcess, this.name) {
|
AdbLogReader._(this._adbProcess, this.name);
|
||||||
_linesController = StreamController<String>.broadcast(
|
|
||||||
onListen: _start,
|
|
||||||
onCancel: _stop,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
factory AdbLogReader.test(Process adbProcess, String name) = AdbLogReader._;
|
factory AdbLogReader.test(Process adbProcess, String name) = AdbLogReader._;
|
||||||
@ -1029,7 +1023,7 @@ class AdbLogReader extends DeviceLogReader {
|
|||||||
}) async {
|
}) async {
|
||||||
// logcat -T is not supported on Android releases before Lollipop.
|
// logcat -T is not supported on Android releases before Lollipop.
|
||||||
const int kLollipopVersionCode = 21;
|
const int kLollipopVersionCode = 21;
|
||||||
final int apiVersion = (String v) {
|
final int? apiVersion = (String? v) {
|
||||||
// If the API version string isn't found, conservatively assume that the
|
// If the API version string isn't found, conservatively assume that the
|
||||||
// version is less recent than the one we're looking for.
|
// version is less recent than the one we're looking for.
|
||||||
return v == null ? kLollipopVersionCode - 1 : int.tryParse(v);
|
return v == null ? kLollipopVersionCode - 1 : int.tryParse(v);
|
||||||
@ -1052,7 +1046,7 @@ class AdbLogReader extends DeviceLogReader {
|
|||||||
} else if (apiVersion != null && apiVersion >= kLollipopVersionCode) {
|
} else if (apiVersion != null && apiVersion >= kLollipopVersionCode) {
|
||||||
// Otherwise, filter for logs appearing past the present.
|
// Otherwise, filter for logs appearing past the present.
|
||||||
// '-T 0` means the timestamp of the logcat command invocation.
|
// '-T 0` means the timestamp of the logcat command invocation.
|
||||||
final String lastLogcatTimestamp = await device.lastLogcatTimestamp();
|
final String? lastLogcatTimestamp = await device.lastLogcatTimestamp();
|
||||||
args.addAll(<String>[
|
args.addAll(<String>[
|
||||||
'-T',
|
'-T',
|
||||||
if (lastLogcatTimestamp != null) "'$lastLogcatTimestamp'" else '0',
|
if (lastLogcatTimestamp != null) "'$lastLogcatTimestamp'" else '0',
|
||||||
@ -1067,7 +1061,10 @@ class AdbLogReader extends DeviceLogReader {
|
|||||||
@override
|
@override
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
StreamController<String> _linesController;
|
late final StreamController<String> _linesController = StreamController<String>.broadcast(
|
||||||
|
onListen: _start,
|
||||||
|
onCancel: _stop,
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<String> get logLines => _linesController.stream;
|
Stream<String> get logLines => _linesController.stream;
|
||||||
@ -1128,14 +1125,14 @@ class AdbLogReader extends DeviceLogReader {
|
|||||||
if (_linesController.isClosed) {
|
if (_linesController.isClosed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Match timeMatch = AndroidDevice._timeRegExp.firstMatch(line);
|
final Match? timeMatch = AndroidDevice._timeRegExp.firstMatch(line);
|
||||||
if (timeMatch == null || line.length == timeMatch.end) {
|
if (timeMatch == null || line.length == timeMatch.end) {
|
||||||
_acceptedLastLine = false;
|
_acceptedLastLine = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Chop off the time.
|
// Chop off the time.
|
||||||
line = line.substring(timeMatch.end + 1);
|
line = line.substring(timeMatch.end + 1);
|
||||||
final Match logMatch = _logFormat.firstMatch(line);
|
final Match? logMatch = _logFormat.firstMatch(line);
|
||||||
if (logMatch != null) {
|
if (logMatch != null) {
|
||||||
bool acceptLine = false;
|
bool acceptLine = false;
|
||||||
|
|
||||||
@ -1143,19 +1140,19 @@ class AdbLogReader extends DeviceLogReader {
|
|||||||
// While a fatal crash is going on, only accept lines from the crash
|
// While a fatal crash is going on, only accept lines from the crash
|
||||||
// Otherwise the crash log in the console may get interrupted
|
// Otherwise the crash log in the console may get interrupted
|
||||||
|
|
||||||
final Match fatalMatch = _tombstoneLine.firstMatch(line);
|
final Match? fatalMatch = _tombstoneLine.firstMatch(line);
|
||||||
|
|
||||||
if (fatalMatch != null) {
|
if (fatalMatch != null) {
|
||||||
acceptLine = true;
|
acceptLine = true;
|
||||||
|
|
||||||
line = fatalMatch[1];
|
line = fatalMatch[1]!;
|
||||||
|
|
||||||
if (_tombstoneTerminator.hasMatch(fatalMatch[1])) {
|
if (_tombstoneTerminator.hasMatch(line)) {
|
||||||
// Hit crash terminator, stop logging the crash info
|
// Hit crash terminator, stop logging the crash info
|
||||||
_fatalCrash = false;
|
_fatalCrash = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (appPid != null && int.parse(logMatch.group(1)) == appPid) {
|
} else if (appPid != null && int.parse(logMatch.group(1)!) == appPid) {
|
||||||
acceptLine = true;
|
acceptLine = true;
|
||||||
|
|
||||||
if (_fatalLog.hasMatch(line)) {
|
if (_fatalLog.hasMatch(line)) {
|
||||||
@ -1189,7 +1186,7 @@ class AdbLogReader extends DeviceLogReader {
|
|||||||
|
|
||||||
void _stop() {
|
void _stop() {
|
||||||
_linesController.close();
|
_linesController.close();
|
||||||
_adbProcess?.kill();
|
_adbProcess.kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1201,10 +1198,10 @@ class AdbLogReader extends DeviceLogReader {
|
|||||||
/// A [DevicePortForwarder] implemented for Android devices that uses adb.
|
/// A [DevicePortForwarder] implemented for Android devices that uses adb.
|
||||||
class AndroidDevicePortForwarder extends DevicePortForwarder {
|
class AndroidDevicePortForwarder extends DevicePortForwarder {
|
||||||
AndroidDevicePortForwarder({
|
AndroidDevicePortForwarder({
|
||||||
@required ProcessManager processManager,
|
required ProcessManager processManager,
|
||||||
@required Logger logger,
|
required Logger logger,
|
||||||
@required String deviceId,
|
required String deviceId,
|
||||||
@required String adbPath,
|
required String adbPath,
|
||||||
}) : _deviceId = deviceId,
|
}) : _deviceId = deviceId,
|
||||||
_adbPath = adbPath,
|
_adbPath = adbPath,
|
||||||
_logger = logger,
|
_logger = logger,
|
||||||
@ -1215,7 +1212,7 @@ class AndroidDevicePortForwarder extends DevicePortForwarder {
|
|||||||
final Logger _logger;
|
final Logger _logger;
|
||||||
final ProcessUtils _processUtils;
|
final ProcessUtils _processUtils;
|
||||||
|
|
||||||
static int _extractPort(String portString) {
|
static int? _extractPort(String portString) {
|
||||||
return int.tryParse(portString.trim());
|
return int.tryParse(portString.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1253,8 +1250,8 @@ class AndroidDevicePortForwarder extends DevicePortForwarder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to extract ports.
|
// Attempt to extract ports.
|
||||||
final int hostPort = _extractPort(splitLine[1]);
|
final int? hostPort = _extractPort(splitLine[1]);
|
||||||
final int devicePort = _extractPort(splitLine[2]);
|
final int? devicePort = _extractPort(splitLine[2]);
|
||||||
|
|
||||||
// Failed, skip.
|
// Failed, skip.
|
||||||
if (hostPort == null || devicePort == null) {
|
if (hostPort == null || devicePort == null) {
|
||||||
@ -1268,7 +1265,7 @@ class AndroidDevicePortForwarder extends DevicePortForwarder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> forward(int devicePort, { int hostPort }) async {
|
Future<int> forward(int devicePort, { int? hostPort }) async {
|
||||||
hostPort ??= 0;
|
hostPort ??= 0;
|
||||||
final RunResult process = await _processUtils.run(
|
final RunResult process = await _processUtils.run(
|
||||||
<String>[
|
<String>[
|
||||||
@ -1320,7 +1317,7 @@ class AndroidDevicePortForwarder extends DevicePortForwarder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hostPort;
|
return hostPort!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1335,7 +1332,6 @@ class AndroidDevicePortForwarder extends DevicePortForwarder {
|
|||||||
'--remove',
|
'--remove',
|
||||||
tcpLine,
|
tcpLine,
|
||||||
],
|
],
|
||||||
throwOnError: false,
|
|
||||||
);
|
);
|
||||||
if (runResult.exitCode == 0) {
|
if (runResult.exitCode == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
import 'package:process/process.dart';
|
import 'package:process/process.dart';
|
||||||
|
|
||||||
import '../base/common.dart';
|
import '../base/common.dart';
|
||||||
@ -29,13 +26,13 @@ import 'android_workflow.dart';
|
|||||||
/// * [AndroidDevice], the type of discovered device.
|
/// * [AndroidDevice], the type of discovered device.
|
||||||
class AndroidDevices extends PollingDeviceDiscovery {
|
class AndroidDevices extends PollingDeviceDiscovery {
|
||||||
AndroidDevices({
|
AndroidDevices({
|
||||||
@required AndroidWorkflow androidWorkflow,
|
required AndroidWorkflow androidWorkflow,
|
||||||
@required ProcessManager processManager,
|
required ProcessManager processManager,
|
||||||
@required Logger logger,
|
required Logger logger,
|
||||||
@required AndroidSdk androidSdk,
|
AndroidSdk? androidSdk,
|
||||||
@required FileSystem fileSystem,
|
required FileSystem fileSystem,
|
||||||
@required Platform platform,
|
required Platform platform,
|
||||||
@required UserMessages userMessages,
|
required UserMessages userMessages,
|
||||||
}) : _androidWorkflow = androidWorkflow,
|
}) : _androidWorkflow = androidWorkflow,
|
||||||
_androidSdk = androidSdk,
|
_androidSdk = androidSdk,
|
||||||
_processUtils = ProcessUtils(
|
_processUtils = ProcessUtils(
|
||||||
@ -51,7 +48,7 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
|
|
||||||
final AndroidWorkflow _androidWorkflow;
|
final AndroidWorkflow _androidWorkflow;
|
||||||
final ProcessUtils _processUtils;
|
final ProcessUtils _processUtils;
|
||||||
final AndroidSdk _androidSdk;
|
final AndroidSdk? _androidSdk;
|
||||||
final ProcessManager _processManager;
|
final ProcessManager _processManager;
|
||||||
final Logger _logger;
|
final Logger _logger;
|
||||||
final FileSystem _fileSystem;
|
final FileSystem _fileSystem;
|
||||||
@ -65,13 +62,13 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
bool get canListAnything => _androidWorkflow.canListDevices;
|
bool get canListAnything => _androidWorkflow.canListDevices;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
|
Future<List<Device>> pollingGetDevices({ Duration? timeout }) async {
|
||||||
if (_doesNotHaveAdb()) {
|
if (_doesNotHaveAdb()) {
|
||||||
return <AndroidDevice>[];
|
return <AndroidDevice>[];
|
||||||
}
|
}
|
||||||
String text;
|
String text;
|
||||||
try {
|
try {
|
||||||
text = (await _processUtils.run(<String>[_androidSdk.adbPath, 'devices', '-l'],
|
text = (await _processUtils.run(<String>[_androidSdk!.adbPath!, 'devices', '-l'],
|
||||||
throwOnError: true,
|
throwOnError: true,
|
||||||
)).stdout.trim();
|
)).stdout.trim();
|
||||||
} on ProcessException catch (exception) {
|
} on ProcessException catch (exception) {
|
||||||
@ -94,7 +91,7 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
return <String>[];
|
return <String>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
final RunResult result = await _processUtils.run(<String>[_androidSdk.adbPath, 'devices', '-l']);
|
final RunResult result = await _processUtils.run(<String>[_androidSdk!.adbPath!, 'devices', '-l']);
|
||||||
if (result.exitCode != 0) {
|
if (result.exitCode != 0) {
|
||||||
return <String>[];
|
return <String>[];
|
||||||
}
|
}
|
||||||
@ -108,8 +105,8 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
|
|
||||||
bool _doesNotHaveAdb() {
|
bool _doesNotHaveAdb() {
|
||||||
return _androidSdk == null ||
|
return _androidSdk == null ||
|
||||||
_androidSdk.adbPath == null ||
|
_androidSdk?.adbPath == null ||
|
||||||
!_processManager.canRun(_androidSdk.adbPath);
|
!_processManager.canRun(_androidSdk!.adbPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 015d172c98400a03 device usb:340787200X product:nakasi model:Nexus_7 device:grouper
|
// 015d172c98400a03 device usb:340787200X product:nakasi model:Nexus_7 device:grouper
|
||||||
@ -120,8 +117,8 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
/// in which case information for that parameter won't be populated.
|
/// in which case information for that parameter won't be populated.
|
||||||
void _parseADBDeviceOutput(
|
void _parseADBDeviceOutput(
|
||||||
String text, {
|
String text, {
|
||||||
List<AndroidDevice> devices,
|
List<AndroidDevice>? devices,
|
||||||
List<String> diagnostics,
|
List<String>? diagnostics,
|
||||||
}) {
|
}) {
|
||||||
// Check for error messages from adb
|
// Check for error messages from adb
|
||||||
if (!text.contains('List of devices')) {
|
if (!text.contains('List of devices')) {
|
||||||
@ -146,11 +143,11 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_kDeviceRegex.hasMatch(line)) {
|
if (_kDeviceRegex.hasMatch(line)) {
|
||||||
final Match match = _kDeviceRegex.firstMatch(line);
|
final Match match = _kDeviceRegex.firstMatch(line)!;
|
||||||
|
|
||||||
final String deviceID = match[1];
|
final String deviceID = match[1]!;
|
||||||
final String deviceState = match[2];
|
final String deviceState = match[2]!;
|
||||||
String rest = match[3];
|
String rest = match[3]!;
|
||||||
|
|
||||||
final Map<String, String> info = <String, String>{};
|
final Map<String, String> info = <String, String>{};
|
||||||
if (rest != null && rest.isNotEmpty) {
|
if (rest != null && rest.isNotEmpty) {
|
||||||
@ -163,8 +160,9 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info['model'] != null) {
|
final String? model = info['model'];
|
||||||
info['model'] = cleanAdbDeviceName(info['model']);
|
if (model != null) {
|
||||||
|
info['model'] = cleanAdbDeviceName(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceState == 'unauthorized') {
|
if (deviceState == 'unauthorized') {
|
||||||
@ -180,7 +178,7 @@ class AndroidDevices extends PollingDeviceDiscovery {
|
|||||||
productID: info['product'],
|
productID: info['product'],
|
||||||
modelID: info['model'] ?? deviceID,
|
modelID: info['model'] ?? deviceID,
|
||||||
deviceCodeName: info['device'],
|
deviceCodeName: info['device'],
|
||||||
androidSdk: _androidSdk,
|
androidSdk: _androidSdk!,
|
||||||
fileSystem: _fileSystem,
|
fileSystem: _fileSystem,
|
||||||
logger: _logger,
|
logger: _logger,
|
||||||
platform: _platform,
|
platform: _platform,
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter_tools/src/android/android_device.dart';
|
import 'package:flutter_tools/src/android/android_device.dart';
|
||||||
@ -183,7 +181,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidDevice createFakeDevice(int sdkLevel) {
|
AndroidDevice createFakeDevice(int? sdkLevel) {
|
||||||
return FakeAndroidDevice(
|
return FakeAndroidDevice(
|
||||||
sdkLevel.toString(),
|
sdkLevel.toString(),
|
||||||
kLastLogcatTimestamp,
|
kLastLogcatTimestamp,
|
||||||
|
@ -72,7 +72,6 @@ void main() {
|
|||||||
|
|
||||||
testWithoutContext('AndroidDevices returns empty device list and diagnostics on null Android SDK', () async {
|
testWithoutContext('AndroidDevices returns empty device list and diagnostics on null Android SDK', () async {
|
||||||
final AndroidDevices androidDevices = AndroidDevices(
|
final AndroidDevices androidDevices = AndroidDevices(
|
||||||
androidSdk: null,
|
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
androidWorkflow: AndroidWorkflow(
|
androidWorkflow: AndroidWorkflow(
|
||||||
androidSdk: FakeAndroidSdk(null),
|
androidSdk: FakeAndroidSdk(null),
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'package:flutter_tools/src/android/android_device.dart';
|
import 'package:flutter_tools/src/android/android_device.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
import 'package:flutter_tools/src/device_port_forwarder.dart';
|
import 'package:flutter_tools/src/device_port_forwarder.dart';
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/android/android_device.dart';
|
import 'package:flutter_tools/src/android/android_device.dart';
|
||||||
import 'package:flutter_tools/src/android/android_sdk.dart';
|
import 'package:flutter_tools/src/android/android_sdk.dart';
|
||||||
@ -42,9 +40,9 @@ const FakeCommand kShaCommand = FakeCommand(
|
|||||||
);
|
);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
FileSystem fileSystem;
|
late FileSystem fileSystem;
|
||||||
FakeProcessManager processManager;
|
late FakeProcessManager processManager;
|
||||||
AndroidSdk androidSdk;
|
late AndroidSdk androidSdk;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
processManager = FakeProcessManager.empty();
|
processManager = FakeProcessManager.empty();
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'package:file/memory.dart';
|
|
||||||
import 'package:flutter_tools/src/android/android_device.dart';
|
|
||||||
import 'package:flutter_tools/src/android/android_sdk.dart';
|
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
|
||||||
import 'package:flutter_tools/src/base/platform.dart';
|
|
||||||
import 'package:test/fake.dart';
|
|
||||||
|
|
||||||
import '../../src/common.dart';
|
|
||||||
import '../../src/fake_process_manager.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWithoutContext('AndroidDevice.stopApp handles a null ApplicationPackage', () async {
|
|
||||||
final AndroidDevice androidDevice = AndroidDevice('1234',
|
|
||||||
androidSdk: FakeAndroidSdk(),
|
|
||||||
fileSystem: MemoryFileSystem.test(),
|
|
||||||
logger: BufferLogger.test(),
|
|
||||||
platform: FakePlatform(),
|
|
||||||
processManager: FakeProcessManager.any(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await androidDevice.stopApp(null), false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class FakeAndroidSdk extends Fake implements AndroidSdk { }
|
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
@ -459,15 +457,16 @@ Uptime: 441088659 Realtime: 521464097
|
|||||||
}
|
}
|
||||||
|
|
||||||
AndroidDevice setUpAndroidDevice({
|
AndroidDevice setUpAndroidDevice({
|
||||||
String id,
|
String? id,
|
||||||
AndroidSdk androidSdk,
|
AndroidSdk? androidSdk,
|
||||||
FileSystem fileSystem,
|
FileSystem? fileSystem,
|
||||||
ProcessManager processManager,
|
ProcessManager? processManager,
|
||||||
Platform platform,
|
Platform? platform,
|
||||||
AndroidConsoleSocketFactory androidConsoleSocketFactory = kAndroidConsoleSocketFactory,
|
AndroidConsoleSocketFactory androidConsoleSocketFactory = kAndroidConsoleSocketFactory,
|
||||||
}) {
|
}) {
|
||||||
androidSdk ??= FakeAndroidSdk();
|
androidSdk ??= FakeAndroidSdk();
|
||||||
return AndroidDevice(id ?? '1234',
|
return AndroidDevice(id ?? '1234',
|
||||||
|
modelID: 'TestModel',
|
||||||
logger: BufferLogger.test(),
|
logger: BufferLogger.test(),
|
||||||
platform: platform ?? FakePlatform(),
|
platform: platform ?? FakePlatform(),
|
||||||
androidSdk: androidSdk,
|
androidSdk: androidSdk,
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'package:file/memory.dart';
|
import 'package:file/memory.dart';
|
||||||
import 'package:flutter_tools/src/android/android_device.dart';
|
import 'package:flutter_tools/src/android/android_device.dart';
|
||||||
import 'package:flutter_tools/src/android/android_sdk.dart';
|
import 'package:flutter_tools/src/android/android_sdk.dart';
|
||||||
@ -41,8 +39,8 @@ const FakeCommand kStoreShaCommand = FakeCommand(
|
|||||||
);
|
);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
FileSystem fileSystem;
|
late FileSystem fileSystem;
|
||||||
BufferLogger logger;
|
late BufferLogger logger;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
fileSystem = MemoryFileSystem.test();
|
fileSystem = MemoryFileSystem.test();
|
||||||
@ -50,15 +48,16 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AndroidDevice setUpAndroidDevice({
|
AndroidDevice setUpAndroidDevice({
|
||||||
AndroidSdk androidSdk,
|
AndroidSdk? androidSdk,
|
||||||
ProcessManager processManager,
|
ProcessManager? processManager,
|
||||||
}) {
|
}) {
|
||||||
androidSdk ??= FakeAndroidSdk();
|
androidSdk ??= FakeAndroidSdk();
|
||||||
return AndroidDevice('1234',
|
return AndroidDevice('1234',
|
||||||
|
modelID: 'TestModel',
|
||||||
logger: logger,
|
logger: logger,
|
||||||
platform: FakePlatform(),
|
platform: FakePlatform(),
|
||||||
androidSdk: androidSdk,
|
androidSdk: androidSdk,
|
||||||
fileSystem: fileSystem ?? MemoryFileSystem.test(),
|
fileSystem: fileSystem,
|
||||||
processManager: processManager ?? FakeProcessManager.any(),
|
processManager: processManager ?? FakeProcessManager.any(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user