Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
88631339
Unverified
Commit
88631339
authored
Jun 08, 2020
by
Jenn Magder
Committed by
GitHub
Jun 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support work profiles and multiple Android users for run, install, attach, drive (#58815)
parent
f0174b17
Changes
23
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
565 additions
and
173 deletions
+565
-173
android_device.dart
packages/flutter_tools/lib/src/android/android_device.dart
+62
-17
attach.dart
packages/flutter_tools/lib/src/commands/attach.dart
+11
-0
drive.dart
packages/flutter_tools/lib/src/commands/drive.dart
+25
-7
install.dart
packages/flutter_tools/lib/src/commands/install.dart
+18
-7
run.dart
packages/flutter_tools/lib/src/commands/run.dart
+12
-0
desktop_device.dart
packages/flutter_tools/lib/src/desktop_device.dart
+17
-4
device.dart
packages/flutter_tools/lib/src/device.dart
+29
-7
fuchsia_device.dart
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+17
-4
devices.dart
packages/flutter_tools/lib/src/ios/devices.dart
+17
-4
simulators.dart
packages/flutter_tools/lib/src/ios/simulators.dart
+17
-4
resident_runner.dart
packages/flutter_tools/lib/src/resident_runner.dart
+10
-4
run_cold.dart
packages/flutter_tools/lib/src/run_cold.dart
+1
-1
flutter_command.dart
packages/flutter_tools/lib/src/runner/flutter_command.dart
+7
-0
flutter_tester.dart
packages/flutter_tools/lib/src/tester/flutter_tester.dart
+18
-5
web_device.dart
packages/flutter_tools/lib/src/web/web_device.dart
+34
-8
attach_test.dart
...utter_tools/test/commands.shard/hermetic/attach_test.dart
+35
-9
drive_test.dart
...lutter_tools/test/commands.shard/hermetic/drive_test.dart
+39
-9
install_test.dart
...tter_tools/test/commands.shard/hermetic/install_test.dart
+21
-2
run_test.dart
.../flutter_tools/test/commands.shard/hermetic/run_test.dart
+34
-0
android_device_start_test.dart
...test/general.shard/android/android_device_start_test.dart
+15
-3
android_install_test.dart
...ools/test/general.shard/android/android_install_test.dart
+74
-26
resident_runner_test.dart
...lutter_tools/test/general.shard/resident_runner_test.dart
+51
-51
resident_web_runner_test.dart
...er_tools/test/general.shard/resident_web_runner_test.dart
+1
-1
No files found.
packages/flutter_tools/lib/src/android/android_device.dart
View file @
88631339
...
...
@@ -389,10 +389,21 @@ class AndroidDevice extends Device {
String
get
name
=>
modelID
;
@override
Future
<
bool
>
isAppInstalled
(
AndroidApk
app
)
async
{
Future
<
bool
>
isAppInstalled
(
AndroidApk
app
,
{
String
userIdentifier
,
})
async
{
// This call takes 400ms - 600ms.
try
{
final
RunResult
listOut
=
await
runAdbCheckedAsync
(<
String
>[
'shell'
,
'pm'
,
'list'
,
'packages'
,
app
.
id
]);
final
RunResult
listOut
=
await
runAdbCheckedAsync
(<
String
>[
'shell'
,
'pm'
,
'list'
,
'packages'
,
if
(
userIdentifier
!=
null
)
...<
String
>[
'--user'
,
userIdentifier
],
app
.
id
]);
return
LineSplitter
.
split
(
listOut
.
stdout
).
contains
(
'package:
${app.id}
'
);
}
on
Exception
catch
(
error
)
{
_logger
.
printTrace
(
'
$error
'
);
...
...
@@ -407,7 +418,10 @@ class AndroidDevice extends Device {
}
@override
Future
<
bool
>
installApp
(
AndroidApk
app
)
async
{
Future
<
bool
>
installApp
(
AndroidApk
app
,
{
String
userIdentifier
,
})
async
{
if
(!
app
.
file
.
existsSync
())
{
_logger
.
printError
(
'"
${_fileSystem.path.relative(app.file.path)}
" does not exist.'
);
return
false
;
...
...
@@ -423,7 +437,14 @@ class AndroidDevice extends Device {
timeout:
_timeoutConfiguration
.
slowOperation
,
);
final
RunResult
installResult
=
await
_processUtils
.
run
(
adbCommandForDevice
(<
String
>[
'install'
,
'-t'
,
'-r'
,
app
.
file
.
path
]));
adbCommandForDevice
(<
String
>[
'install'
,
'-t'
,
'-r'
,
if
(
userIdentifier
!=
null
)
...<
String
>[
'--user'
,
userIdentifier
],
app
.
file
.
path
]));
status
.
stop
();
// Some versions of adb exit with exit code 0 even on failure :(
// Parsing the output to check for failures.
...
...
@@ -434,8 +455,12 @@ class AndroidDevice extends Device {
return
false
;
}
if
(
installResult
.
exitCode
!=
0
)
{
_logger
.
printError
(
'Error: ADB exited with exit code
${installResult.exitCode}
'
);
_logger
.
printError
(
'
$installResult
'
);
if
(
installResult
.
stderr
.
contains
(
'Bad user number'
))
{
_logger
.
printError
(
'Error: User "
$userIdentifier
" not found. Run "adb shell pm list users" to see list of available identifiers.'
);
}
else
{
_logger
.
printError
(
'Error: ADB exited with exit code
${installResult.exitCode}
'
);
_logger
.
printError
(
'
$installResult
'
);
}
return
false
;
}
try
{
...
...
@@ -450,7 +475,10 @@ class AndroidDevice extends Device {
}
@override
Future
<
bool
>
uninstallApp
(
AndroidApk
app
)
async
{
Future
<
bool
>
uninstallApp
(
AndroidApk
app
,
{
String
userIdentifier
,
})
async
{
if
(!
await
_checkForSupportedAdbVersion
()
||
!
await
_checkForSupportedAndroidVersion
())
{
return
false
;
...
...
@@ -459,7 +487,11 @@ class AndroidDevice extends Device {
String
uninstallOut
;
try
{
final
RunResult
uninstallResult
=
await
_processUtils
.
run
(
adbCommandForDevice
(<
String
>[
'uninstall'
,
app
.
id
]),
adbCommandForDevice
(<
String
>[
'uninstall'
,
if
(
userIdentifier
!=
null
)
...<
String
>[
'--user'
,
userIdentifier
],
app
.
id
]),
throwOnError:
true
,
);
uninstallOut
=
uninstallResult
.
stdout
;
...
...
@@ -477,8 +509,8 @@ class AndroidDevice extends Device {
return
true
;
}
Future
<
bool
>
_installLatestApp
(
AndroidApk
package
)
async
{
final
bool
wasInstalled
=
await
isAppInstalled
(
package
);
Future
<
bool
>
_installLatestApp
(
AndroidApk
package
,
String
userIdentifier
)
async
{
final
bool
wasInstalled
=
await
isAppInstalled
(
package
,
userIdentifier:
userIdentifier
);
if
(
wasInstalled
)
{
if
(
await
isLatestBuildInstalled
(
package
))
{
_logger
.
printTrace
(
'Latest build already installed.'
);
...
...
@@ -486,15 +518,15 @@ class AndroidDevice extends Device {
}
}
_logger
.
printTrace
(
'Installing APK.'
);
if
(!
await
installApp
(
package
))
{
if
(!
await
installApp
(
package
,
userIdentifier:
userIdentifier
))
{
_logger
.
printTrace
(
'Warning: Failed to install APK.'
);
if
(
wasInstalled
)
{
_logger
.
printStatus
(
'Uninstalling old version...'
);
if
(!
await
uninstallApp
(
package
))
{
if
(!
await
uninstallApp
(
package
,
userIdentifier:
userIdentifier
))
{
_logger
.
printError
(
'Error: Uninstalling old version failed.'
);
return
false
;
}
if
(!
await
installApp
(
package
))
{
if
(!
await
installApp
(
package
,
userIdentifier:
userIdentifier
))
{
_logger
.
printError
(
'Error: Failed to install APK again.'
);
return
false
;
}
...
...
@@ -516,6 +548,7 @@ class AndroidDevice extends Device {
Map
<
String
,
dynamic
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
if
(!
await
_checkForSupportedAdbVersion
()
||
!
await
_checkForSupportedAndroidVersion
())
{
...
...
@@ -570,9 +603,9 @@ class AndroidDevice extends Device {
}
_logger
.
printTrace
(
"Stopping app '
${package.name}
' on
$name
."
);
await
stopApp
(
package
);
await
stopApp
(
package
,
userIdentifier:
userIdentifier
);
if
(!
await
_installLatestApp
(
package
))
{
if
(!
await
_installLatestApp
(
package
,
userIdentifier
))
{
return
LaunchResult
.
failed
();
}
...
...
@@ -636,6 +669,8 @@ class AndroidDevice extends Device {
...<
String
>[
'--ez'
,
'use-test-fonts'
,
'true'
],
if
(
debuggingOptions
.
verboseSystemLogs
)
...<
String
>[
'--ez'
,
'verbose-logging'
,
'true'
],
if
(
userIdentifier
!=
null
)
...<
String
>[
'--user'
,
userIdentifier
],
],
package
.
launchActivity
,
];
...
...
@@ -687,11 +722,21 @@ class AndroidDevice extends Device {
bool
get
supportsFastStart
=>
true
;
@override
Future
<
bool
>
stopApp
(
AndroidApk
app
)
{
Future
<
bool
>
stopApp
(
AndroidApk
app
,
{
String
userIdentifier
,
})
{
if
(
app
==
null
)
{
return
Future
<
bool
>.
value
(
false
);
}
final
List
<
String
>
command
=
adbCommandForDevice
(<
String
>[
'shell'
,
'am'
,
'force-stop'
,
app
.
id
]);
final
List
<
String
>
command
=
adbCommandForDevice
(<
String
>[
'shell'
,
'am'
,
'force-stop'
,
if
(
userIdentifier
!=
null
)
...<
String
>[
'--user'
,
userIdentifier
],
app
.
id
,
]);
return
_processUtils
.
stream
(
command
).
then
<
bool
>(
(
int
exitCode
)
=>
exitCode
==
0
||
allowHeapCorruptionOnWindows
(
exitCode
,
_platform
));
}
...
...
packages/flutter_tools/lib/src/commands/attach.dart
View file @
88631339
...
...
@@ -63,6 +63,7 @@ class AttachCommand extends FlutterCommand {
usesFilesystemOptions
(
hide:
!
verboseHelp
);
usesFuchsiaOptions
(
hide:
!
verboseHelp
);
usesDartDefineOption
();
usesDeviceUserOption
();
argParser
..
addOption
(
'debug-port'
,
...
...
@@ -136,6 +137,8 @@ class AttachCommand extends FlutterCommand {
return
stringArg
(
'app-id'
);
}
String
get
userIdentifier
=>
stringArg
(
FlutterOptions
.
kDeviceUser
);
@override
Future
<
void
>
validateCommand
()
async
{
await
super
.
validateCommand
();
...
...
@@ -159,6 +162,13 @@ class AttachCommand extends FlutterCommand {
throwToolExit
(
'Either --debugPort or --debugUri can be provided, not both.'
);
}
if
(
userIdentifier
!=
null
)
{
final
Device
device
=
await
findTargetDevice
();
if
(
device
is
!
AndroidDevice
)
{
throwToolExit
(
'--
${FlutterOptions.kDeviceUser}
is only supported for Android'
);
}
}
}
@override
...
...
@@ -356,6 +366,7 @@ class AttachCommand extends FlutterCommand {
target:
stringArg
(
'target'
),
targetModel:
TargetModel
(
stringArg
(
'target-model'
)),
buildInfo:
getBuildInfo
(),
userIdentifier:
userIdentifier
,
);
flutterDevice
.
observatoryUris
=
observatoryUris
;
final
List
<
FlutterDevice
>
flutterDevices
=
<
FlutterDevice
>[
flutterDevice
];
...
...
packages/flutter_tools/lib/src/commands/drive.dart
View file @
88631339
...
...
@@ -10,6 +10,7 @@ import 'package:vm_service/vm_service.dart' as vm_service;
import
'package:meta/meta.dart'
;
import
'package:webdriver/async_io.dart'
as
async_io
;
import
'../android/android_device.dart'
;
import
'../application_package.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
...
...
@@ -22,7 +23,7 @@ import '../device.dart';
import
'../globals.dart'
as
globals
;
import
'../project.dart'
;
import
'../resident_runner.dart'
;
import
'../runner/flutter_command.dart'
show
FlutterCommandResult
;
import
'../runner/flutter_command.dart'
show
FlutterCommandResult
,
FlutterOptions
;
import
'../vmservice.dart'
;
import
'../web/web_runner.dart'
;
import
'run.dart'
;
...
...
@@ -136,11 +137,23 @@ class DriveCommand extends RunCommandBase {
bool
get
shouldBuild
=>
boolArg
(
'build'
);
bool
get
verboseSystemLogs
=>
boolArg
(
'verbose-system-logs'
);
String
get
userIdentifier
=>
stringArg
(
FlutterOptions
.
kDeviceUser
);
/// Subscription to log messages printed on the device or simulator.
// ignore: cancel_subscriptions
StreamSubscription
<
String
>
_deviceLogSubscription
;
@override
Future
<
void
>
validateCommand
()
async
{
if
(
userIdentifier
!=
null
)
{
final
Device
device
=
await
findTargetDevice
();
if
(
device
is
!
AndroidDevice
)
{
throwToolExit
(
'--
${FlutterOptions.kDeviceUser}
is only supported for Android'
);
}
}
return
super
.
validateCommand
();
}
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
final
String
testFile
=
_getTestFile
();
...
...
@@ -195,7 +208,7 @@ class DriveCommand extends RunCommandBase {
device
,
flutterProject:
flutterProject
,
target:
targetFile
,
buildInfo:
buildInfo
buildInfo:
buildInfo
,
);
residentRunner
=
webRunnerFactory
.
createWebRunner
(
flutterDevice
,
...
...
@@ -412,7 +425,11 @@ void restoreAppStarter() {
appStarter
=
_startApp
;
}
Future
<
LaunchResult
>
_startApp
(
DriveCommand
command
,
Uri
webUri
)
async
{
Future
<
LaunchResult
>
_startApp
(
DriveCommand
command
,
Uri
webUri
,
{
String
userIdentifier
,
})
async
{
final
String
mainPath
=
findMainDartFile
(
command
.
targetFile
);
if
(
await
globals
.
fs
.
type
(
mainPath
)
!=
FileSystemEntityType
.
file
)
{
globals
.
printError
(
'Tried to run
$mainPath
, but that file does not exist.'
);
...
...
@@ -427,10 +444,10 @@ Future<LaunchResult> _startApp(DriveCommand command, Uri webUri) async {
if
(
command
.
shouldBuild
)
{
globals
.
printTrace
(
'Installing application package.'
);
if
(
await
command
.
device
.
isAppInstalled
(
package
))
{
await
command
.
device
.
uninstallApp
(
package
);
if
(
await
command
.
device
.
isAppInstalled
(
package
,
userIdentifier:
userIdentifier
))
{
await
command
.
device
.
uninstallApp
(
package
,
userIdentifier:
userIdentifier
);
}
await
command
.
device
.
installApp
(
package
);
await
command
.
device
.
installApp
(
package
,
userIdentifier:
userIdentifier
);
}
final
Map
<
String
,
dynamic
>
platformArgs
=
<
String
,
dynamic
>{};
...
...
@@ -469,6 +486,7 @@ Future<LaunchResult> _startApp(DriveCommand command, Uri webUri) async {
),
platformArgs:
platformArgs
,
prebuiltApplication:
!
command
.
shouldBuild
,
userIdentifier:
userIdentifier
,
);
if
(!
result
.
started
)
{
...
...
@@ -520,7 +538,7 @@ Future<bool> _stopApp(DriveCommand command) async {
await
command
.
device
.
targetPlatform
,
command
.
getBuildInfo
(),
);
final
bool
stopped
=
await
command
.
device
.
stopApp
(
package
);
final
bool
stopped
=
await
command
.
device
.
stopApp
(
package
,
userIdentifier:
command
.
userIdentifier
);
await
command
.
_deviceLogSubscription
?.
cancel
();
return
stopped
;
}
...
...
packages/flutter_tools/lib/src/commands/install.dart
View file @
88631339
...
...
@@ -4,6 +4,7 @@
import
'dart:async'
;
import
'../android/android_device.dart'
;
import
'../application_package.dart'
;
import
'../base/common.dart'
;
import
'../base/io.dart'
;
...
...
@@ -15,6 +16,7 @@ import '../runner/flutter_command.dart';
class
InstallCommand
extends
FlutterCommand
with
DeviceBasedDevelopmentArtifacts
{
InstallCommand
()
{
requiresPubspecYaml
();
usesDeviceUserOption
();
argParser
.
addFlag
(
'uninstall-only'
,
negatable:
true
,
defaultsTo:
false
,
...
...
@@ -31,6 +33,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
Device
device
;
bool
get
uninstallOnly
=>
boolArg
(
'uninstall-only'
);
String
get
userIdentifier
=>
stringArg
(
FlutterOptions
.
kDeviceUser
);
@override
Future
<
void
>
validateCommand
()
async
{
...
...
@@ -39,6 +42,9 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
if
(
device
==
null
)
{
throwToolExit
(
'No target device found'
);
}
if
(
userIdentifier
!=
null
&&
device
is
!
AndroidDevice
)
{
throwToolExit
(
'--
${FlutterOptions.kDeviceUser}
is only supported for Android'
);
}
}
@override
...
...
@@ -59,9 +65,9 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
}
Future
<
void
>
_uninstallApp
(
ApplicationPackage
package
)
async
{
if
(
await
device
.
isAppInstalled
(
package
))
{
if
(
await
device
.
isAppInstalled
(
package
,
userIdentifier:
userIdentifier
))
{
globals
.
printStatus
(
'Uninstalling
$package
from
$device
...'
);
if
(!
await
device
.
uninstallApp
(
package
))
{
if
(!
await
device
.
uninstallApp
(
package
,
userIdentifier:
userIdentifier
))
{
globals
.
printError
(
'Uninstalling old version failed'
);
}
}
else
{
...
...
@@ -72,21 +78,26 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
Future
<
void
>
_installApp
(
ApplicationPackage
package
)
async
{
globals
.
printStatus
(
'Installing
$package
to
$device
...'
);
if
(!
await
installApp
(
device
,
package
))
{
if
(!
await
installApp
(
device
,
package
,
userIdentifier:
userIdentifier
))
{
throwToolExit
(
'Install failed'
);
}
}
}
Future
<
bool
>
installApp
(
Device
device
,
ApplicationPackage
package
,
{
bool
uninstall
=
true
})
async
{
Future
<
bool
>
installApp
(
Device
device
,
ApplicationPackage
package
,
{
String
userIdentifier
,
bool
uninstall
=
true
})
async
{
if
(
package
==
null
)
{
return
false
;
}
try
{
if
(
uninstall
&&
await
device
.
isAppInstalled
(
package
))
{
if
(
uninstall
&&
await
device
.
isAppInstalled
(
package
,
userIdentifier:
userIdentifier
))
{
globals
.
printStatus
(
'Uninstalling old version...'
);
if
(!
await
device
.
uninstallApp
(
package
))
{
if
(!
await
device
.
uninstallApp
(
package
,
userIdentifier:
userIdentifier
))
{
globals
.
printError
(
'Warning: uninstalling old version failed'
);
}
}
...
...
@@ -94,5 +105,5 @@ Future<bool> installApp(Device device, ApplicationPackage package, { bool uninst
globals
.
printError
(
'Error accessing device
${device.id}
:
\n
${e.message}
'
);
}
return
device
.
installApp
(
package
);
return
device
.
installApp
(
package
,
userIdentifier:
userIdentifier
);
}
packages/flutter_tools/lib/src/commands/run.dart
View file @
88631339
...
...
@@ -6,6 +6,7 @@ import 'dart:async';
import
'package:args/command_runner.dart'
;
import
'../android/android_device.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
...
...
@@ -67,6 +68,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
usesTrackWidgetCreation
(
verboseHelp:
verboseHelp
);
usesIsolateFilterOption
(
hide:
!
verboseHelp
);
addNullSafetyModeOptions
();
usesDeviceUserOption
();
}
bool
get
traceStartup
=>
boolArg
(
'trace-startup'
);
...
...
@@ -221,6 +223,8 @@ class RunCommand extends RunCommandBase {
List
<
Device
>
devices
;
String
get
userIdentifier
=>
stringArg
(
FlutterOptions
.
kDeviceUser
);
@override
Future
<
String
>
get
usagePath
async
{
final
String
command
=
await
super
.
usagePath
;
...
...
@@ -336,6 +340,13 @@ class RunCommand extends RunCommandBase {
if
(
deviceManager
.
hasSpecifiedAllDevices
&&
runningWithPrebuiltApplication
)
{
throwToolExit
(
'Using -d all with --use-application-binary is not supported'
);
}
if
(
userIdentifier
!=
null
&&
devices
.
every
((
Device
device
)
=>
device
is
!
AndroidDevice
))
{
throwToolExit
(
'--
${FlutterOptions.kDeviceUser}
is only supported for Android. At least one Android device is required.'
);
}
}
DebuggingOptions
_createDebuggingOptions
()
{
...
...
@@ -491,6 +502,7 @@ class RunCommand extends RunCommandBase {
experimentalFlags:
expFlags
,
target:
stringArg
(
'target'
),
buildInfo:
getBuildInfo
(),
userIdentifier:
userIdentifier
,
),
];
// Only support "web mode" with a single web device due to resident runner
...
...
packages/flutter_tools/lib/src/desktop_device.dart
View file @
88631339
...
...
@@ -33,7 +33,10 @@ abstract class DesktopDevice extends Device {
// Since the host and target devices are the same, no work needs to be done
// to install the application.
@override
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
// Since the host and target devices are the same, no work needs to be done
// to install the application.
...
...
@@ -43,12 +46,18 @@ abstract class DesktopDevice extends Device {
// Since the host and target devices are the same, no work needs to be done
// to install the application.
@override
Future
<
bool
>
installApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
installApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
// Since the host and target devices are the same, no work needs to be done
// to uninstall the application.
@override
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
Future
<
bool
>
get
isLocalEmulator
async
=>
false
;
...
...
@@ -86,6 +95,7 @@ abstract class DesktopDevice extends Device {
Map
<
String
,
dynamic
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
if
(!
prebuiltApplication
)
{
Cache
.
releaseLockEarly
();
...
...
@@ -138,7 +148,10 @@ abstract class DesktopDevice extends Device {
}
@override
Future
<
bool
>
stopApp
(
ApplicationPackage
app
)
async
{
Future
<
bool
>
stopApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
{
bool
succeeded
=
true
;
// Walk a copy of _runningProcesses, since the exit handler removes from the
// set.
...
...
packages/flutter_tools/lib/src/device.dart
View file @
88631339
...
...
@@ -413,17 +413,33 @@ abstract class Device {
/// Whether the device is supported for the current project directory.
bool
isSupportedForProject
(
FlutterProject
flutterProject
);
/// Check if a version of the given app is already installed
Future
<
bool
>
isAppInstalled
(
covariant
ApplicationPackage
app
);
/// Check if a version of the given app is already installed.
///
/// Specify [userIdentifier] to check if installed for a particular user (Android only).
Future
<
bool
>
isAppInstalled
(
covariant
ApplicationPackage
app
,
{
String
userIdentifier
,
});
/// Check if the latest build of the [app] is already installed.
Future
<
bool
>
isLatestBuildInstalled
(
covariant
ApplicationPackage
app
);
/// Install an app package on the current device
Future
<
bool
>
installApp
(
covariant
ApplicationPackage
app
);
/// Install an app package on the current device.
///
/// Specify [userIdentifier] to install for a particular user (Android only).
Future
<
bool
>
installApp
(
covariant
ApplicationPackage
app
,
{
String
userIdentifier
,
});
/// Uninstall an app package from the current device
Future
<
bool
>
uninstallApp
(
covariant
ApplicationPackage
app
);
/// Uninstall an app package from the current device.
///
/// Specify [userIdentifier] to uninstall for a particular user,
/// defaults to all users (Android only).
Future
<
bool
>
uninstallApp
(
covariant
ApplicationPackage
app
,
{
String
userIdentifier
,
});
/// Check if the device is supported by Flutter
bool
isSupported
();
...
...
@@ -471,6 +487,7 @@ abstract class Device {
Map
<
String
,
dynamic
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
});
/// Whether this device implements support for hot reload.
...
...
@@ -491,7 +508,12 @@ abstract class Device {
bool
get
supportsFastStart
=>
false
;
/// Stop an app package on the current device.
Future
<
bool
>
stopApp
(
covariant
ApplicationPackage
app
);
///
/// Specify [userIdentifier] to stop app installed to a profile (Android only).
Future
<
bool
>
stopApp
(
covariant
ApplicationPackage
app
,
{
String
userIdentifier
,
});
/// Query the current application memory usage..
///
...
...
packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
View file @
88631339
...
...
@@ -237,16 +237,25 @@ class FuchsiaDevice extends Device {
bool
get
supportsStartPaused
=>
false
;
@override
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
)
async
=>
false
;
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
false
;
@override
Future
<
bool
>
isLatestBuildInstalled
(
ApplicationPackage
app
)
async
=>
false
;
@override
Future
<
bool
>
installApp
(
ApplicationPackage
app
)
=>
Future
<
bool
>.
value
(
false
);
Future
<
bool
>
installApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
=>
Future
<
bool
>.
value
(
false
);
@override
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
)
async
=>
false
;
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
false
;
@override
bool
isSupported
()
=>
true
;
...
...
@@ -263,6 +272,7 @@ class FuchsiaDevice extends Device {
Map
<
String
,
dynamic
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
if
(!
prebuiltApplication
)
{
await
buildFuchsia
(
fuchsiaProject:
FlutterProject
.
current
().
fuchsia
,
...
...
@@ -434,7 +444,10 @@ class FuchsiaDevice extends Device {
}
@override
Future
<
bool
>
stopApp
(
covariant
FuchsiaApp
app
)
async
{
Future
<
bool
>
stopApp
(
covariant
FuchsiaApp
app
,
{
String
userIdentifier
,
})
async
{
final
int
appKey
=
await
FuchsiaTilesCtl
.
findAppKey
(
this
,
app
.
id
);
if
(
appKey
!=
-
1
)
{
if
(!
await
fuchsiaDeviceTools
.
tilesCtl
.
remove
(
this
,
appKey
))
{
...
...
packages/flutter_tools/lib/src/ios/devices.dart
View file @
88631339
...
...
@@ -225,7 +225,10 @@ class IOSDevice extends Device {
bool
get
supportsStartPaused
=>
false
;
@override
Future
<
bool
>
isAppInstalled
(
IOSApp
app
)
async
{
Future
<
bool
>
isAppInstalled
(
IOSApp
app
,
{
String
userIdentifier
,
})
async
{
bool
result
;
try
{
result
=
await
_iosDeploy
.
isAppInstalled
(
...
...
@@ -243,7 +246,10 @@ class IOSDevice extends Device {
Future
<
bool
>
isLatestBuildInstalled
(
IOSApp
app
)
async
=>
false
;
@override
Future
<
bool
>
installApp
(
IOSApp
app
)
async
{
Future
<
bool
>
installApp
(
IOSApp
app
,
{
String
userIdentifier
,
})
async
{
final
Directory
bundle
=
_fileSystem
.
directory
(
app
.
deviceBundlePath
);
if
(!
bundle
.
existsSync
())
{
_logger
.
printError
(
'Could not find application bundle at
${bundle.path}
; have you run "flutter build ios"?'
);
...
...
@@ -273,7 +279,10 @@ class IOSDevice extends Device {
}
@override
Future
<
bool
>
uninstallApp
(
IOSApp
app
)
async
{
Future
<
bool
>
uninstallApp
(
IOSApp
app
,
{
String
userIdentifier
,
})
async
{
int
uninstallationResult
;
try
{
uninstallationResult
=
await
_iosDeploy
.
uninstallApp
(
...
...
@@ -304,6 +313,7 @@ class IOSDevice extends Device {
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
@visibleForTesting
Duration
fallbackPollingDelay
,
String
userIdentifier
,
})
async
{
String
packageId
;
...
...
@@ -443,7 +453,10 @@ class IOSDevice extends Device {
}
@override
Future
<
bool
>
stopApp
(
IOSApp
app
)
async
{
Future
<
bool
>
stopApp
(
IOSApp
app
,
{
String
userIdentifier
,
})
async
{
// Currently we don't have a way to stop an app running on iOS.
return
false
;
}
...
...
packages/flutter_tools/lib/src/ios/simulators.dart
View file @
88631339
...
...
@@ -319,7 +319,10 @@ class IOSSimulator extends Device {
String
get
xcrunPath
=>
globals
.
fs
.
path
.
join
(
'/usr'
,
'bin'
,
'xcrun'
);
@override
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
)
{
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
{
return
_simControl
.
isInstalled
(
id
,
app
.
id
);
}
...
...
@@ -327,7 +330,10 @@ class IOSSimulator extends Device {
Future
<
bool
>
isLatestBuildInstalled
(
ApplicationPackage
app
)
async
=>
false
;
@override
Future
<
bool
>
installApp
(
covariant
IOSApp
app
)
async
{
Future
<
bool
>
installApp
(
covariant
IOSApp
app
,
{
String
userIdentifier
,
})
async
{
try
{
final
IOSApp
iosApp
=
app
;
await
_simControl
.
install
(
id
,
iosApp
.
simulatorBundlePath
);
...
...
@@ -338,7 +344,10 @@ class IOSSimulator extends Device {
}
@override
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
)
async
{
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
{
try
{
await
_simControl
.
uninstall
(
id
,
app
.
id
);
return
true
;
...
...
@@ -384,6 +393,7 @@ class IOSSimulator extends Device {
Map
<
String
,
dynamic
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
if
(!
prebuiltApplication
&&
package
is
BuildableIOSApp
)
{
globals
.
printTrace
(
'Building
${package.name}
for
$id
.'
);
...
...
@@ -495,7 +505,10 @@ class IOSSimulator extends Device {
}
@override
Future
<
bool
>
stopApp
(
ApplicationPackage
app
)
async
{
Future
<
bool
>
stopApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
{
// Currently we don't have a way to stop an app running on iOS.
return
false
;
}
...
...
packages/flutter_tools/lib/src/resident_runner.dart
View file @
88631339
...
...
@@ -47,6 +47,7 @@ class FlutterDevice {
TargetModel
targetModel
=
TargetModel
.
flutter
,
TargetPlatform
targetPlatform
,
ResidentCompiler
generator
,
this
.
userIdentifier
,
})
:
assert
(
buildInfo
.
trackWidgetCreation
!=
null
),
generator
=
generator
??
ResidentCompiler
(
globals
.
artifacts
.
getArtifactPath
(
...
...
@@ -76,6 +77,7 @@ class FlutterDevice {
TargetModel
targetModel
=
TargetModel
.
flutter
,
List
<
String
>
experimentalFlags
,
ResidentCompiler
generator
,
String
userIdentifier
,
})
async
{
ResidentCompiler
generator
;
final
TargetPlatform
targetPlatform
=
await
device
.
targetPlatform
;
...
...
@@ -150,12 +152,14 @@ class FlutterDevice {
targetPlatform:
targetPlatform
,
generator:
generator
,
buildInfo:
buildInfo
,
userIdentifier:
userIdentifier
,
);
}
final
Device
device
;
final
ResidentCompiler
generator
;
final
BuildInfo
buildInfo
;
final
String
userIdentifier
;
Stream
<
Uri
>
observatoryUris
;
vm_service
.
VmService
vmService
;
DevFS
devFS
;
...
...
@@ -239,11 +243,11 @@ class FlutterDevice {
@visibleForTesting
Duration
timeoutDelay
=
const
Duration
(
seconds:
10
),
})
async
{
if
(!
device
.
supportsFlutterExit
||
vmService
==
null
)
{
return
device
.
stopApp
(
package
);
return
device
.
stopApp
(
package
,
userIdentifier:
userIdentifier
);
}
final
List
<
FlutterView
>
views
=
await
vmService
.
getFlutterViews
();
if
(
views
==
null
||
views
.
isEmpty
)
{
return
device
.
stopApp
(
package
);
return
device
.
stopApp
(
package
,
userIdentifier:
userIdentifier
);
}
// If any of the flutter views are paused, we might not be able to
// cleanly exit since the service extension may not have been registered.
...
...
@@ -254,7 +258,7 @@ class FlutterDevice {
continue
;
}
if
(
isPauseEvent
(
isolate
.
pauseEvent
.
kind
))
{
return
device
.
stopApp
(
package
);
return
device
.
stopApp
(
package
,
userIdentifier:
userIdentifier
);
}
}
for
(
final
FlutterView
view
in
views
)
{
...
...
@@ -277,7 +281,7 @@ class FlutterDevice {
// flutter_attach_android_test. This log should help verify this
// is where the tool is getting stuck.
globals
.
logger
.
printTrace
(
'error: vm service shutdown failed'
);
return
device
.
stopApp
(
package
);
return
device
.
stopApp
(
package
,
userIdentifier:
userIdentifier
);
});
}
...
...
@@ -502,6 +506,7 @@ class FlutterDevice {
route:
route
,
prebuiltApplication:
prebuiltMode
,
ipv6:
hotRunner
.
ipv6
,
userIdentifier:
userIdentifier
,
);
final
LaunchResult
result
=
await
futureResult
;
...
...
@@ -575,6 +580,7 @@ class FlutterDevice {
route:
route
,
prebuiltApplication:
prebuiltMode
,
ipv6:
coldRunner
.
ipv6
,
userIdentifier:
userIdentifier
,
);
if
(!
result
.
started
)
{
...
...
packages/flutter_tools/lib/src/run_cold.dart
View file @
88631339
...
...
@@ -202,7 +202,7 @@ class ColdRunner extends ResidentRunner {
for
(
final
FlutterDevice
device
in
flutterDevices
)
{
// If we're running in release mode, stop the app using the device logic.
if
(
device
.
vmService
==
null
)
{
await
device
.
device
.
stopApp
(
device
.
package
);
await
device
.
device
.
stopApp
(
device
.
package
,
userIdentifier:
device
.
userIdentifier
);
}
}
await
super
.
preExit
();
...
...
packages/flutter_tools/lib/src/runner/flutter_command.dart
View file @
88631339
...
...
@@ -110,6 +110,7 @@ class FlutterOptions {
static
const
String
kBundleSkSLPathOption
=
'bundle-sksl-path'
;
static
const
String
kPerformanceMeasurementFile
=
'performance-measurement-file'
;
static
const
String
kNullSafety
=
'sound-null-safety'
;
static
const
String
kDeviceUser
=
'device-user'
;
}
abstract
class
FlutterCommand
extends
Command
<
void
>
{
...
...
@@ -374,6 +375,12 @@ abstract class FlutterCommand extends Command<void> {
"Normally there's only one, but when adding Flutter to a pre-existing app it's possible to create multiple."
);
}
void
usesDeviceUserOption
()
{
argParser
.
addOption
(
FlutterOptions
.
kDeviceUser
,
help:
'Identifier number for a user or work profile on Android only. Run "adb shell pm list users" for available identifiers.'
,
valueHelp:
'10'
);
}
void
addBuildModeFlags
({
bool
defaultToRelease
=
true
,
bool
verboseHelp
=
false
,
bool
excludeDebug
=
false
})
{
// A release build must be the default if a debug build is not possible.
assert
(
defaultToRelease
||
!
excludeDebug
);
...
...
packages/flutter_tools/lib/src/tester/flutter_tester.dart
View file @
88631339
...
...
@@ -90,10 +90,16 @@ class FlutterTesterDevice extends Device {
}
@override
Future
<
bool
>
installApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
installApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
)
async
=>
false
;
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
false
;
@override
Future
<
bool
>
isLatestBuildInstalled
(
ApplicationPackage
app
)
async
=>
false
;
...
...
@@ -109,10 +115,11 @@ class FlutterTesterDevice extends Device {
ApplicationPackage
package
,
{
@required
String
mainPath
,
String
route
,
@required
DebuggingOptions
debuggingOptions
,
DebuggingOptions
debuggingOptions
,
Map
<
String
,
dynamic
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
final
BuildInfo
buildInfo
=
debuggingOptions
.
buildInfo
;
...
...
@@ -218,14 +225,20 @@ class FlutterTesterDevice extends Device {
}
@override
Future
<
bool
>
stopApp
(
ApplicationPackage
app
)
async
{
Future
<
bool
>
stopApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
{
_process
?.
kill
();
_process
=
null
;
return
true
;
}
@override
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
bool
isSupportedForProject
(
FlutterProject
flutterProject
)
=>
true
;
...
...
packages/flutter_tools/lib/src/web/web_device.dart
View file @
88631339
...
...
@@ -87,10 +87,16 @@ abstract class ChromiumDevice extends Device {
}
@override
Future
<
bool
>
installApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
installApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
Future
<
bool
>
isLatestBuildInstalled
(
ApplicationPackage
app
)
async
=>
true
;
...
...
@@ -116,6 +122,7 @@ abstract class ChromiumDevice extends Device {
Map
<
String
,
Object
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
// See [ResidentWebRunner.run] in flutter_tools/lib/src/resident_web_runner.dart
// for the web initialization and server logic.
...
...
@@ -137,7 +144,10 @@ abstract class ChromiumDevice extends Device {
}
@override
Future
<
bool
>
stopApp
(
ApplicationPackage
app
)
async
{
Future
<
bool
>
stopApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
{
await
_chrome
?.
close
();
return
true
;
}
...
...
@@ -146,7 +156,10 @@ abstract class ChromiumDevice extends Device {
Future
<
TargetPlatform
>
get
targetPlatform
async
=>
TargetPlatform
.
web_javascript
;
@override
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
bool
isSupportedForProject
(
FlutterProject
flutterProject
)
{
...
...
@@ -333,10 +346,16 @@ class WebServerDevice extends Device {
}
@override
Future
<
bool
>
installApp
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
installApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
)
async
=>
true
;
Future
<
bool
>
isAppInstalled
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
=>
true
;
@override
Future
<
bool
>
isLatestBuildInstalled
(
ApplicationPackage
app
)
async
=>
true
;
...
...
@@ -375,6 +394,7 @@ class WebServerDevice extends Device {
Map
<
String
,
Object
>
platformArgs
,
bool
prebuiltApplication
=
false
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
final
String
url
=
platformArgs
[
'uri'
]
as
String
;
if
(
debuggingOptions
.
startPaused
)
{
...
...
@@ -387,7 +407,10 @@ class WebServerDevice extends Device {
}
@override
Future
<
bool
>
stopApp
(
ApplicationPackage
app
)
async
{
Future
<
bool
>
stopApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
{
return
true
;
}
...
...
@@ -395,7 +418,10 @@ class WebServerDevice extends Device {
Future
<
TargetPlatform
>
get
targetPlatform
async
=>
TargetPlatform
.
web_javascript
;
@override
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
)
async
{
Future
<
bool
>
uninstallApp
(
ApplicationPackage
app
,
{
String
userIdentifier
,
})
async
{
return
true
;
}
...
...
packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart
View file @
88631339
...
...
@@ -326,16 +326,29 @@ void main() {
globals
.
fs
.
file
(
globals
.
fs
.
path
.
join
(
'lib'
,
'main.dart'
)).
deleteSync
();
final
AttachCommand
command
=
AttachCommand
(
hotRunnerFactory:
mockHotRunnerFactory
);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'attach'
,
'-t'
,
foo
.
path
,
'-v'
]);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'attach'
,
'-t'
,
foo
.
path
,
'-v'
,
'--device-user'
,
'10'
,
]);
final
VerificationResult
verificationResult
=
verify
(
mockHotRunnerFactory
.
build
(
captureAny
,
target:
foo
.
path
,
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
packagesFilePath:
anyNamed
(
'packagesFilePath'
),
flutterProject:
anyNamed
(
'flutterProject'
),
ipv6:
false
,
),
)..
called
(
1
);
verify
(
mockHotRunnerFactory
.
build
(
any
,
target:
foo
.
path
,
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
packagesFilePath:
anyNamed
(
'packagesFilePath'
),
flutterProject:
anyNamed
(
'flutterProject'
),
ipv6:
false
,
)).
called
(
1
);
final
List
<
FlutterDevice
>
flutterDevices
=
verificationResult
.
captured
.
first
as
List
<
FlutterDevice
>;
expect
(
flutterDevices
,
hasLength
(
1
));
final
FlutterDevice
flutterDevice
=
flutterDevices
.
first
;
expect
(
flutterDevice
.
userIdentifier
,
'10'
);
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
...
...
@@ -538,6 +551,19 @@ void main() {
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'fails when targeted device is not Android with --device-user'
,
()
async
{
final
MockIOSDevice
device
=
MockIOSDevice
();
testDeviceManager
.
addDevice
(
device
);
expect
(
createTestCommandRunner
(
AttachCommand
()).
run
(<
String
>[
'attach'
,
'--device-user'
,
'10'
,
]),
throwsToolExit
(
message:
'--device-user is only supported for Android'
));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
testFileSystem
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'exits when multiple devices connected'
,
()
async
{
Device
aDeviceWithId
(
String
id
)
{
final
MockAndroidDevice
device
=
MockAndroidDevice
();
...
...
packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart
View file @
88631339
...
...
@@ -166,9 +166,30 @@ void main() {
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'returns
0 when test ends successfully
'
,
()
async
{
testUsingContext
(
'returns
1 when targeted device is not Android with --device-user
'
,
()
async
{
testDeviceManager
.
addDevice
(
MockDevice
());
final
String
testApp
=
globals
.
fs
.
path
.
join
(
tempDir
.
path
,
'test'
,
'e2e.dart'
);
globals
.
fs
.
file
(
testApp
).
createSync
(
recursive:
true
);
final
List
<
String
>
args
=
<
String
>[
'drive'
,
'--target=
$testApp
'
,
'--no-pub'
,
'--device-user'
,
'10'
,
];
expect
(()
async
=>
await
createTestCommandRunner
(
command
).
run
(
args
),
throwsToolExit
(
message:
'--device-user is only supported for Android'
));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
});
testUsingContext
(
'returns 0 when test ends successfully'
,
()
async
{
testDeviceManager
.
addDevice
(
MockAndroidDevice
());
final
String
testApp
=
globals
.
fs
.
path
.
join
(
tempDir
.
path
,
'test'
,
'e2e.dart'
);
final
String
testFile
=
globals
.
fs
.
path
.
join
(
tempDir
.
path
,
'test_driver'
,
'e2e_test.dart'
);
...
...
@@ -195,6 +216,8 @@ void main() {
'drive'
,
'--target=
$testApp
'
,
'--no-pub'
,
'--device-user'
,
'10'
,
];
await
createTestCommandRunner
(
command
).
run
(
args
);
expect
(
testLogger
.
errorText
,
isEmpty
);
...
...
@@ -358,14 +381,16 @@ void main() {
final
MockLaunchResult
mockLaunchResult
=
MockLaunchResult
();
when
(
mockLaunchResult
.
started
).
thenReturn
(
true
);
when
(
mockDevice
.
startApp
(
null
,
mainPath:
anyNamed
(
'mainPath'
),
route:
anyNamed
(
'route'
),
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
platformArgs:
anyNamed
(
'platformArgs'
),
prebuiltApplication:
anyNamed
(
'prebuiltApplication'
),
null
,
mainPath:
anyNamed
(
'mainPath'
),
route:
anyNamed
(
'route'
),
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
platformArgs:
anyNamed
(
'platformArgs'
),
prebuiltApplication:
anyNamed
(
'prebuiltApplication'
),
userIdentifier:
anyNamed
(
'userIdentifier'
),
)).
thenAnswer
((
_
)
=>
Future
<
LaunchResult
>.
value
(
mockLaunchResult
));
when
(
mockDevice
.
isAppInstalled
(
any
)).
thenAnswer
((
_
)
=>
Future
<
bool
>.
value
(
false
));
when
(
mockDevice
.
isAppInstalled
(
any
,
userIdentifier:
anyNamed
(
'userIdentifier'
)))
.
thenAnswer
((
_
)
=>
Future
<
bool
>.
value
(
false
));
testApp
=
globals
.
fs
.
path
.
join
(
tempDir
.
path
,
'test'
,
'e2e.dart'
);
testFile
=
globals
.
fs
.
path
.
join
(
tempDir
.
path
,
'test_driver'
,
'e2e_test.dart'
);
...
...
@@ -407,6 +432,7 @@ void main() {
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
platformArgs:
anyNamed
(
'platformArgs'
),
prebuiltApplication:
false
,
userIdentifier:
anyNamed
(
'userIdentifier'
),
));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
...
...
@@ -435,6 +461,7 @@ void main() {
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
platformArgs:
anyNamed
(
'platformArgs'
),
prebuiltApplication:
false
,
userIdentifier:
anyNamed
(
'userIdentifier'
),
));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
...
...
@@ -463,6 +490,7 @@ void main() {
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
platformArgs:
anyNamed
(
'platformArgs'
),
prebuiltApplication:
true
,
userIdentifier:
anyNamed
(
'userIdentifier'
),
));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
fs
,
...
...
@@ -494,11 +522,12 @@ void main() {
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
platformArgs:
anyNamed
(
'platformArgs'
),
prebuiltApplication:
anyNamed
(
'prebuiltApplication'
),
userIdentifier:
anyNamed
(
'userIdentifier'
),
)).
thenAnswer
((
Invocation
invocation
)
async
{
debuggingOptions
=
invocation
.
namedArguments
[
#debuggingOptions
]
as
DebuggingOptions
;
return
mockLaunchResult
;
});
when
(
mockDevice
.
isAppInstalled
(
any
))
when
(
mockDevice
.
isAppInstalled
(
any
,
userIdentifier:
anyNamed
(
'userIdentifier'
)
))
.
thenAnswer
((
_
)
=>
Future
<
bool
>.
value
(
false
));
testApp
=
globals
.
fs
.
path
.
join
(
tempDir
.
path
,
'test'
,
'e2e.dart'
);
...
...
@@ -547,6 +576,7 @@ void main() {
debuggingOptions:
anyNamed
(
'debuggingOptions'
),
platformArgs:
anyNamed
(
'platformArgs'
),
prebuiltApplication:
false
,
userIdentifier:
anyNamed
(
'userIdentifier'
),
));
expect
(
optionValue
(),
setToTrue
?
isTrue
:
isFalse
);
},
overrides:
<
Type
,
Generator
>{
...
...
packages/flutter_tools/test/commands.shard/hermetic/install_test.dart
View file @
88631339
...
...
@@ -21,8 +21,10 @@ void main() {
applyMocksToCommand
(
command
);
final
MockAndroidDevice
device
=
MockAndroidDevice
();
when
(
device
.
isAppInstalled
(
any
)).
thenAnswer
((
_
)
async
=>
false
);
when
(
device
.
installApp
(
any
)).
thenAnswer
((
_
)
async
=>
true
);
when
(
device
.
isAppInstalled
(
any
,
userIdentifier:
anyNamed
(
'userIdentifier'
)))
.
thenAnswer
((
_
)
async
=>
false
);
when
(
device
.
installApp
(
any
,
userIdentifier:
anyNamed
(
'userIdentifier'
)))
.
thenAnswer
((
_
)
async
=>
true
);
testDeviceManager
.
addDevice
(
device
);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'install'
]);
...
...
@@ -30,6 +32,23 @@ void main() {
Cache:
()
=>
MockCache
(),
});
testUsingContext
(
'returns 1 when targeted device is not Android with --device-user'
,
()
async
{
final
InstallCommand
command
=
InstallCommand
();
applyMocksToCommand
(
command
);
final
MockIOSDevice
device
=
MockIOSDevice
();
when
(
device
.
isAppInstalled
(
any
,
userIdentifier:
anyNamed
(
'userIdentifier'
)))
.
thenAnswer
((
_
)
async
=>
false
);
when
(
device
.
installApp
(
any
,
userIdentifier:
anyNamed
(
'userIdentifier'
)))
.
thenAnswer
((
_
)
async
=>
true
);
testDeviceManager
.
addDevice
(
device
);
expect
(()
async
=>
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'install'
,
'--device-user'
,
'10'
]),
throwsToolExit
(
message:
'--device-user is only supported for Android'
));
},
overrides:
<
Type
,
Generator
>{
Cache:
()
=>
MockCache
(),
});
testUsingContext
(
'returns 0 when iOS is connected and ready for an install'
,
()
async
{
final
InstallCommand
command
=
InstallCommand
();
applyMocksToCommand
(
command
);
...
...
packages/flutter_tools/test/commands.shard/hermetic/run_test.dart
View file @
88631339
...
...
@@ -203,6 +203,38 @@ void main() {
ProcessManager:
()
=>
mockProcessManager
,
});
testUsingContext
(
'fails when targeted device is not Android with --device-user'
,
()
async
{
globals
.
fs
.
file
(
'pubspec.yaml'
).
createSync
();
globals
.
fs
.
file
(
'.packages'
).
writeAsStringSync
(
'
\n
'
);
globals
.
fs
.
file
(
'lib/main.dart'
).
createSync
(
recursive:
true
);
final
FakeDevice
device
=
FakeDevice
(
isLocalEmulator:
true
);
when
(
deviceManager
.
getAllConnectedDevices
()).
thenAnswer
((
Invocation
invocation
)
async
{
return
<
Device
>[
device
];
});
when
(
deviceManager
.
getDevices
()).
thenAnswer
((
Invocation
invocation
)
async
{
return
<
Device
>[
device
];
});
when
(
deviceManager
.
findTargetDevices
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
return
<
Device
>[
device
];
});
when
(
deviceManager
.
hasSpecifiedAllDevices
).
thenReturn
(
false
);
when
(
deviceManager
.
deviceDiscoverers
).
thenReturn
(<
DeviceDiscovery
>[]);
final
RunCommand
command
=
RunCommand
();
applyMocksToCommand
(
command
);
await
expectLater
(
createTestCommandRunner
(
command
).
run
(<
String
>[
'run'
,
'--no-pub'
,
'--device-user'
,
'10'
,
]),
throwsToolExit
(
message:
'--device-user is only supported for Android. At least one Android device is required.'
));
},
overrides:
<
Type
,
Generator
>{
FileSystem:
()
=>
MemoryFileSystem
.
test
(),
ProcessManager:
()
=>
FakeProcessManager
.
any
(),
DeviceManager:
()
=>
MockDeviceManager
(),
Stdio:
()
=>
mockStdio
,
});
testUsingContext
(
'shows unsupported devices when no supported devices are found'
,
()
async
{
final
RunCommand
command
=
RunCommand
();
applyMocksToCommand
(
command
);
...
...
@@ -320,6 +352,7 @@ void main() {
route:
anyNamed
(
'route'
),
prebuiltApplication:
anyNamed
(
'prebuiltApplication'
),
ipv6:
anyNamed
(
'ipv6'
),
userIdentifier:
anyNamed
(
'userIdentifier'
),
)).
thenAnswer
((
Invocation
invocation
)
=>
Future
<
LaunchResult
>.
value
(
LaunchResult
.
failed
()));
when
(
mockArtifacts
.
getArtifactPath
(
...
...
@@ -690,6 +723,7 @@ class FakeDevice extends Fake implements Device {
bool
prebuiltApplication
=
false
,
bool
usesTerminalUi
=
true
,
bool
ipv6
=
false
,
String
userIdentifier
,
})
async
{
final
String
dartFlags
=
debuggingOptions
.
dartFlags
;
// In release mode, --dart-flags should be set to the empty string and
...
...
packages/flutter_tools/test/general.shard/android/android_device_start_test.dart
View file @
88631339
...
...
@@ -188,17 +188,27 @@ void main() {
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'shell'
,
'getprop'
],
));
processManager
.
addCommand
(
const
FakeCommand
(
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'shell'
,
'am'
,
'force-stop'
,
'FlutterApp'
],
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'shell'
,
'am'
,
'force-stop'
,
'
--user'
,
'10'
,
'
FlutterApp'
],
));
processManager
.
addCommand
(
const
FakeCommand
(
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'shell'
,
'pm'
,
'list'
,
'packages'
,
'FlutterApp'
],
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'shell'
,
'pm'
,
'list'
,
'packages'
,
'
--user'
,
'10'
,
'
FlutterApp'
],
));
processManager
.
addCommand
(
kAdbVersionCommand
);
processManager
.
addCommand
(
kStartServer
);
// TODO(jonahwilliams): investigate why this doesn't work.
// This doesn't work with the current Android log reader implementation.
processManager
.
addCommand
(
const
FakeCommand
(
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'install'
,
'-t'
,
'-r'
,
'app.apk'
],
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'install'
,
'-t'
,
'-r'
,
'--user'
,
'10'
,
'app.apk'
],
stdout:
'
\n\n
Observatory listening on http://127.0.0.1:456
\n\n
'
,
));
processManager
.
addCommand
(
kShaCommand
);
...
...
@@ -244,6 +254,7 @@ void main() {
'--es'
,
'dart-flags'
,
'foo'
,
'--ez'
,
'use-test-fonts'
,
'true'
,
'--ez'
,
'verbose-logging'
,
'true'
,
'--user'
,
'10'
,
'FlutterActivity'
,
],
));
...
...
@@ -268,6 +279,7 @@ void main() {
verboseSystemLogs:
true
,
),
platformArgs:
<
String
,
dynamic
>{},
userIdentifier:
'10'
,
);
// This fails to start due to observatory discovery issues.
...
...
packages/flutter_tools/test/general.shard/android/android_install_test.dart
View file @
88631339
...
...
@@ -22,13 +22,46 @@ const FakeCommand kAdbStartServerCommand = FakeCommand(
command:
<
String
>[
'adb'
,
'start-server'
]
);
const
FakeCommand
kInstallCommand
=
FakeCommand
(
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'install'
,
'-t'
,
'-r'
,
'app.apk'
],
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'install'
,
'-t'
,
'-r'
,
'--user'
,
'10'
,
'app.apk'
],
);
const
FakeCommand
kStoreShaCommand
=
FakeCommand
(
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'shell'
,
'echo'
,
'-n'
,
''
,
'>'
,
'/data/local/tmp/sky.app.sha1'
]
);
void
main
(
)
{
FileSystem
fileSystem
;
BufferLogger
logger
;
setUp
(()
{
fileSystem
=
MemoryFileSystem
.
test
();
logger
=
BufferLogger
.
test
();
});
AndroidDevice
setUpAndroidDevice
({
AndroidSdk
androidSdk
,
ProcessManager
processManager
,
})
{
androidSdk
??=
MockAndroidSdk
();
when
(
androidSdk
.
adbPath
).
thenReturn
(
'adb'
);
return
AndroidDevice
(
'1234'
,
logger:
logger
,
platform:
FakePlatform
(
operatingSystem:
'linux'
),
androidSdk:
androidSdk
,
fileSystem:
fileSystem
??
MemoryFileSystem
.
test
(),
processManager:
processManager
??
FakeProcessManager
.
any
(),
);
}
testWithoutContext
(
'Cannot install app on API level below 16'
,
()
async
{
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
kAdbVersionCommand
,
...
...
@@ -38,7 +71,6 @@ void main() {
stdout:
'[ro.build.version.sdk]: [11]'
,
),
]);
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
File
apk
=
fileSystem
.
file
(
'app.apk'
)..
createSync
();
final
AndroidApk
androidApk
=
AndroidApk
(
file:
apk
,
...
...
@@ -47,7 +79,6 @@ void main() {
launchActivity:
'Main'
,
);
final
AndroidDevice
androidDevice
=
setUpAndroidDevice
(
fileSystem:
fileSystem
,
processManager:
processManager
,
);
...
...
@@ -56,7 +87,6 @@ void main() {
});
testWithoutContext
(
'Cannot install app if APK file is missing'
,
()
async
{
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
File
apk
=
fileSystem
.
file
(
'app.apk'
);
final
AndroidApk
androidApk
=
AndroidApk
(
file:
apk
,
...
...
@@ -65,7 +95,6 @@ void main() {
launchActivity:
'Main'
,
);
final
AndroidDevice
androidDevice
=
setUpAndroidDevice
(
fileSystem:
fileSystem
,
);
expect
(
await
androidDevice
.
installApp
(
androidApk
),
false
);
...
...
@@ -82,7 +111,6 @@ void main() {
kInstallCommand
,
kStoreShaCommand
,
]);
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
File
apk
=
fileSystem
.
file
(
'app.apk'
)..
createSync
();
final
AndroidApk
androidApk
=
AndroidApk
(
file:
apk
,
...
...
@@ -91,11 +119,10 @@ void main() {
launchActivity:
'Main'
,
);
final
AndroidDevice
androidDevice
=
setUpAndroidDevice
(
fileSystem:
fileSystem
,
processManager:
processManager
,
);
expect
(
await
androidDevice
.
installApp
(
androidApk
),
true
);
expect
(
await
androidDevice
.
installApp
(
androidApk
,
userIdentifier:
'10'
),
true
);
expect
(
processManager
.
hasRemainingExpectations
,
false
);
});
...
...
@@ -109,7 +136,6 @@ void main() {
kInstallCommand
,
kStoreShaCommand
,
]);
final
FileSystem
fileSystem
=
MemoryFileSystem
.
test
();
final
File
apk
=
fileSystem
.
file
(
'app.apk'
)..
createSync
();
final
AndroidApk
androidApk
=
AndroidApk
(
file:
apk
,
...
...
@@ -118,29 +144,51 @@ void main() {
launchActivity:
'Main'
,
);
final
AndroidDevice
androidDevice
=
setUpAndroidDevice
(
fileSystem:
fileSystem
,
processManager:
processManager
,
);
expect
(
await
androidDevice
.
installApp
(
androidApk
),
true
);
expect
(
await
androidDevice
.
installApp
(
androidApk
,
userIdentifier:
'10'
),
true
);
expect
(
processManager
.
hasRemainingExpectations
,
false
);
});
}
AndroidDevice
setUpAndroidDevice
(
{
AndroidSdk
androidSdk
,
FileSystem
fileSystem
,
ProcessManager
processManager
,
})
{
androidSdk
??=
MockAndroidSdk
();
when
(
androidSdk
.
adbPath
).
thenReturn
(
'adb'
);
return
AndroidDevice
(
'1234'
,
logger:
BufferLogger
.
test
(),
platform:
FakePlatform
(
operatingSystem:
'linux'
),
androidSdk:
androidSdk
,
fileSystem:
fileSystem
??
MemoryFileSystem
.
test
(),
processManager:
processManager
??
FakeProcessManager
.
any
(),
);
testWithoutContext
(
'displays error if user not found'
,
()
async
{
final
FakeProcessManager
processManager
=
FakeProcessManager
.
list
(<
FakeCommand
>[
kAdbVersionCommand
,
kAdbStartServerCommand
,
const
FakeCommand
(
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'shell'
,
'getprop'
],
),
const
FakeCommand
(
command:
<
String
>[
'adb'
,
'-s'
,
'1234'
,
'install'
,
'-t'
,
'-r'
,
'--user'
,
'jane'
,
'app.apk'
],
exitCode:
1
,
stderr:
'Exception occurred while executing: java.lang.IllegalArgumentException: Bad user number: jane'
,
),
]);
final
File
apk
=
fileSystem
.
file
(
'app.apk'
)..
createSync
();
final
AndroidApk
androidApk
=
AndroidApk
(
file:
apk
,
id:
'app'
,
versionCode:
22
,
launchActivity:
'Main'
,
);
final
AndroidDevice
androidDevice
=
setUpAndroidDevice
(
processManager:
processManager
,
);
expect
(
await
androidDevice
.
installApp
(
androidApk
,
userIdentifier:
'jane'
),
false
);
expect
(
logger
.
errorText
,
contains
(
'Error: User "jane" not found. Run "adb shell pm list users" to see list of available identifiers.'
));
expect
(
processManager
.
hasRemainingExpectations
,
false
);
});
}
class
MockAndroidSdk
extends
Mock
implements
AndroidSdk
{}
packages/flutter_tools/test/general.shard/resident_runner_test.dart
View file @
88631339
This diff is collapsed.
Click to expand it.
packages/flutter_tools/test/general.shard/resident_web_runner_test.dart
View file @
88631339
...
...
@@ -1080,7 +1080,7 @@ void main() {
]);
_setupMocks
();
bool
debugClosed
=
false
;
when
(
mockDevice
.
stopApp
(
any
)).
thenAnswer
((
Invocation
invocation
)
async
{
when
(
mockDevice
.
stopApp
(
any
,
userIdentifier:
anyNamed
(
'userIdentifier'
)
)).
thenAnswer
((
Invocation
invocation
)
async
{
if
(
debugClosed
)
{
throw
StateError
(
'debug connection closed twice'
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment