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
8bb8e1d9
Commit
8bb8e1d9
authored
Jan 19, 2016
by
Devon Carew
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add device notifications to the daemon command
parent
477530f3
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
240 additions
and
66 deletions
+240
-66
daemon.dart
packages/flutter_tools/lib/src/commands/daemon.dart
+181
-45
device.dart
packages/flutter_tools/lib/src/device.dart
+26
-10
daemon_test.dart
packages/flutter_tools/test/daemon_test.dart
+19
-6
daemon_client.dart
packages/flutter_tools/tool/daemon_client.dart
+14
-5
No files found.
packages/flutter_tools/lib/src/commands/daemon.dart
View file @
8bb8e1d9
...
@@ -6,21 +6,14 @@ import 'dart:async';
...
@@ -6,21 +6,14 @@ import 'dart:async';
import
'dart:convert'
;
import
'dart:convert'
;
import
'dart:io'
;
import
'dart:io'
;
import
'../android/adb.dart'
;
import
'../base/logging.dart'
;
import
'../base/logging.dart'
;
import
'../device.dart'
;
import
'../runner/flutter_command.dart'
;
import
'../runner/flutter_command.dart'
;
import
'start.dart'
;
import
'start.dart'
;
import
'stop.dart'
;
import
'stop.dart'
;
const
String
protocolVersion
=
'0.0.1'
;
const
String
protocolVersion
=
'0.0.2'
;
/// A @domain annotation.
const
String
domain
=
'domain'
;
/// A domain @command annotation.
const
String
command
=
'command'
;
// TODO: Create a `device` domain in order to list devices and fire events when
// devices are added or removed.
/// A server process command. This command will start up a long-lived server.
/// A server process command. This command will start up a long-lived server.
/// It reads JSON-RPC based commands from stdin, executes them, and returns
/// It reads JSON-RPC based commands from stdin, executes them, and returns
...
@@ -32,7 +25,6 @@ class DaemonCommand extends FlutterCommand {
...
@@ -32,7 +25,6 @@ class DaemonCommand extends FlutterCommand {
final
String
name
=
'daemon'
;
final
String
name
=
'daemon'
;
final
String
description
=
'Run a persistent, JSON-RPC based server to communicate with devices.'
;
final
String
description
=
'Run a persistent, JSON-RPC based server to communicate with devices.'
;
@override
Future
<
int
>
runInProject
()
async
{
Future
<
int
>
runInProject
()
async
{
print
(
'Starting device daemon...'
);
print
(
'Starting device daemon...'
);
...
@@ -48,90 +40,101 @@ class DaemonCommand extends FlutterCommand {
...
@@ -48,90 +40,101 @@ class DaemonCommand extends FlutterCommand {
await
downloadApplicationPackagesAndConnectToDevices
();
await
downloadApplicationPackagesAndConnectToDevices
();
Daemon
daemon
=
new
Daemon
(
commandStream
,
(
Map
command
)
{
Daemon
daemon
=
new
Daemon
(
commandStream
,
(
Map
command
)
{
stdout
.
writeln
(
'[
${JSON.encode(command)}
]'
);
stdout
.
writeln
(
'[
${JSON.encode(command
, toEncodable: _jsonEncodeObject
)}
]'
);
},
daemonCommand:
this
);
},
daemonCommand:
this
);
return
await
daemon
.
onExit
;
return
await
daemon
.
onExit
;
}
}
dynamic
_jsonEncodeObject
(
dynamic
object
)
{
if
(
object
is
Device
)
return
_deviceToMap
(
object
);
return
object
;
}
}
}
typedef
void
DispatchComand
(
Map
command
);
typedef
void
DispatchComand
(
Map
<
String
,
dynamic
>
command
);
typedef
Future
<
dynamic
>
CommandHandler
(
dynamic
args
);
typedef
Future
<
dynamic
>
CommandHandler
(
dynamic
args
);
class
Daemon
{
class
Daemon
{
final
DispatchComand
sendCommand
;
final
DaemonCommand
daemonCommand
;
final
Completer
<
int
>
_onExitCompleter
=
new
Completer
();
final
Map
<
String
,
Domain
>
_domains
=
{};
Daemon
(
Stream
<
Map
>
commandStream
,
this
.
sendCommand
,
{
this
.
daemonCommand
})
{
Daemon
(
Stream
<
Map
>
commandStream
,
this
.
sendCommand
,
{
this
.
daemonCommand
})
{
// Set up domains.
// Set up domains.
_registerDomain
(
new
DaemonDomain
(
this
));
_registerDomain
(
new
DaemonDomain
(
this
));
_registerDomain
(
new
AppDomain
(
this
));
_registerDomain
(
new
AppDomain
(
this
));
_registerDomain
(
new
DeviceDomain
(
this
));
// Start listening.
// Start listening.
commandStream
.
listen
(
commandStream
.
listen
(
(
Map
command
)
=>
_handleCommand
(
command
),
(
Map
request
)
=>
_handleRequest
(
request
),
onDone:
()
=>
_onExitCompleter
.
complete
(
0
)
onDone:
()
=>
_onExitCompleter
.
complete
(
0
)
);
);
}
}
final
DispatchComand
sendCommand
;
final
DaemonCommand
daemonCommand
;
final
Completer
<
int
>
_onExitCompleter
=
new
Completer
<
int
>();
final
Map
<
String
,
Domain
>
_domainMap
=
<
String
,
Domain
>{};
void
_registerDomain
(
Domain
domain
)
{
void
_registerDomain
(
Domain
domain
)
{
_domain
s
[
domain
.
name
]
=
domain
;
_domain
Map
[
domain
.
name
]
=
domain
;
}
}
Future
<
int
>
get
onExit
=>
_onExitCompleter
.
future
;
Future
<
int
>
get
onExit
=>
_onExitCompleter
.
future
;
void
_handleCommand
(
Map
command
)
{
void
_handleRequest
(
Map
request
)
{
// {id, event, params}
// {id, method, params}
var
id
=
command
[
'id'
];
// [id] is an opaque type to us.
dynamic
id
=
request
[
'id'
];
if
(
id
==
null
)
{
if
(
id
==
null
)
{
logging
.
severe
(
'no id for
command:
$command
'
);
logging
.
severe
(
'no id for
request:
$request
'
);
return
;
return
;
}
}
try
{
try
{
String
event
=
command
[
'event
'
];
String
method
=
request
[
'method
'
];
if
(
event
.
indexOf
(
'.'
)
==
-
1
)
if
(
method
.
indexOf
(
'.'
)
==
-
1
)
throw
'
command not understood:
$event
'
;
throw
'
method not understood:
$method
'
;
String
prefix
=
event
.
substring
(
0
,
event
.
indexOf
(
'.'
));
String
prefix
=
method
.
substring
(
0
,
method
.
indexOf
(
'.'
));
String
name
=
event
.
substring
(
event
.
indexOf
(
'.'
)
+
1
);
String
name
=
method
.
substring
(
method
.
indexOf
(
'.'
)
+
1
);
if
(
_domain
s
[
prefix
]
==
null
)
if
(
_domain
Map
[
prefix
]
==
null
)
throw
'no domain for
command:
$comman
d
'
;
throw
'no domain for
method:
$metho
d
'
;
_domain
s
[
prefix
].
handleEvent
(
name
,
id
,
command
[
'params'
]);
_domain
Map
[
prefix
].
handleCommand
(
name
,
id
,
request
[
'params'
]);
}
catch
(
error
,
trace
)
{
}
catch
(
error
,
trace
)
{
_send
({
'id'
:
id
,
'error'
:
_toJsonable
(
error
)});
_send
({
'id'
:
id
,
'error'
:
_toJsonable
(
error
)});
logging
.
warning
(
'error handling
$
{command['event']}
'
,
error
,
trace
);
logging
.
warning
(
'error handling
$
request
'
,
error
,
trace
);
}
}
}
}
void
_send
(
Map
map
)
=>
sendCommand
(
map
);
void
_send
(
Map
map
)
=>
sendCommand
(
map
);
void
shutdown
()
{
void
shutdown
()
{
_domainMap
.
values
.
forEach
((
Domain
domain
)
=>
domain
.
dispose
());
if
(!
_onExitCompleter
.
isCompleted
)
if
(!
_onExitCompleter
.
isCompleted
)
_onExitCompleter
.
complete
(
0
);
_onExitCompleter
.
complete
(
0
);
}
}
}
}
abstract
class
Domain
{
abstract
class
Domain
{
Domain
(
this
.
daemon
,
this
.
name
);
final
Daemon
daemon
;
final
Daemon
daemon
;
final
String
name
;
final
String
name
;
final
Map
<
String
,
CommandHandler
>
_handlers
=
{};
final
Map
<
String
,
CommandHandler
>
_handlers
=
{};
Domain
(
this
.
daemon
,
this
.
name
);
void
registerHandler
(
String
name
,
CommandHandler
handler
)
{
void
registerHandler
(
String
name
,
CommandHandler
handler
)
{
_handlers
[
name
]
=
handler
;
_handlers
[
name
]
=
handler
;
}
}
String
toString
()
=>
name
;
String
toString
()
=>
name
;
void
handle
Event
(
String
name
,
dynamic
id
,
dynamic
args
)
{
void
handle
Command
(
String
name
,
dynamic
id
,
dynamic
args
)
{
new
Future
.
sync
(()
{
new
Future
.
sync
(()
{
if
(
_handlers
.
containsKey
(
name
))
if
(
_handlers
.
containsKey
(
name
))
return
_handlers
[
name
](
args
);
return
_handlers
[
name
](
args
);
...
@@ -148,24 +151,30 @@ abstract class Domain {
...
@@ -148,24 +151,30 @@ abstract class Domain {
});
});
}
}
void
sendEvent
(
String
name
,
[
dynamic
args
])
{
Map
<
String
,
dynamic
>
map
=
{
'method'
:
name
};
if
(
args
!=
null
)
map
[
'params'
]
=
_toJsonable
(
args
);
_send
(
map
);
}
void
_send
(
Map
map
)
=>
daemon
.
_send
(
map
);
void
_send
(
Map
map
)
=>
daemon
.
_send
(
map
);
void
dispose
()
{
}
}
}
/// This domain responds to methods like [version] and [shutdown].
/// This domain responds to methods like [version] and [shutdown].
@domain
class
DaemonDomain
extends
Domain
{
class
DaemonDomain
extends
Domain
{
DaemonDomain
(
Daemon
daemon
)
:
super
(
daemon
,
'daemon'
)
{
DaemonDomain
(
Daemon
daemon
)
:
super
(
daemon
,
'daemon'
)
{
registerHandler
(
'version'
,
version
);
registerHandler
(
'version'
,
version
);
registerHandler
(
'shutdown'
,
shutdown
);
registerHandler
(
'shutdown'
,
shutdown
);
}
}
@command
Future
<
String
>
version
(
dynamic
args
)
{
Future
<
dynamic
>
version
(
dynamic
args
)
{
return
new
Future
.
value
(
protocolVersion
);
return
new
Future
.
value
(
protocolVersion
);
}
}
@command
Future
shutdown
(
dynamic
args
)
{
Future
<
dynamic
>
shutdown
(
dynamic
args
)
{
Timer
.
run
(()
=>
daemon
.
shutdown
());
Timer
.
run
(()
=>
daemon
.
shutdown
());
return
new
Future
.
value
();
return
new
Future
.
value
();
}
}
...
@@ -175,14 +184,12 @@ class DaemonDomain extends Domain {
...
@@ -175,14 +184,12 @@ class DaemonDomain extends Domain {
///
///
/// It'll be extended to fire events for when applications start, stop, and
/// It'll be extended to fire events for when applications start, stop, and
/// log data.
/// log data.
@domain
class
AppDomain
extends
Domain
{
class
AppDomain
extends
Domain
{
AppDomain
(
Daemon
daemon
)
:
super
(
daemon
,
'app'
)
{
AppDomain
(
Daemon
daemon
)
:
super
(
daemon
,
'app'
)
{
registerHandler
(
'start'
,
start
);
registerHandler
(
'start'
,
start
);
registerHandler
(
'stopAll'
,
stopAll
);
registerHandler
(
'stopAll'
,
stopAll
);
}
}
@command
Future
<
dynamic
>
start
(
dynamic
args
)
{
Future
<
dynamic
>
start
(
dynamic
args
)
{
// TODO: Add the ability to pass args: target, http, checked
// TODO: Add the ability to pass args: target, http, checked
StartCommand
startComand
=
new
StartCommand
();
StartCommand
startComand
=
new
StartCommand
();
...
@@ -190,7 +197,6 @@ class AppDomain extends Domain {
...
@@ -190,7 +197,6 @@ class AppDomain extends Domain {
return
startComand
.
runInProject
().
then
((
_
)
=>
null
);
return
startComand
.
runInProject
().
then
((
_
)
=>
null
);
}
}
@command
Future
<
bool
>
stopAll
(
dynamic
args
)
{
Future
<
bool
>
stopAll
(
dynamic
args
)
{
StopCommand
stopCommand
=
new
StopCommand
();
StopCommand
stopCommand
=
new
StopCommand
();
stopCommand
.
inheritFromParent
(
daemon
.
daemonCommand
);
stopCommand
.
inheritFromParent
(
daemon
.
daemonCommand
);
...
@@ -198,8 +204,138 @@ class AppDomain extends Domain {
...
@@ -198,8 +204,138 @@ class AppDomain extends Domain {
}
}
}
}
/// This domain lets callers list and monitor connected devices.
///
/// It exports a `getDevices()` call, as well as firing `device.added`,
/// `device.removed`, and `device.changed` events.
class
DeviceDomain
extends
Domain
{
DeviceDomain
(
Daemon
daemon
)
:
super
(
daemon
,
'device'
)
{
registerHandler
(
'getDevices'
,
getDevices
);
_androidDeviceDiscovery
=
new
AndroidDeviceDiscovery
();
_androidDeviceDiscovery
.
onAdded
.
listen
((
Device
device
)
{
sendEvent
(
'device.added'
,
_deviceToMap
(
device
));
});
_androidDeviceDiscovery
.
onRemoved
.
listen
((
Device
device
)
{
sendEvent
(
'device.removed'
,
_deviceToMap
(
device
));
});
_androidDeviceDiscovery
.
onChanged
.
listen
((
Device
device
)
{
sendEvent
(
'device.changed'
,
_deviceToMap
(
device
));
});
}
AndroidDeviceDiscovery
_androidDeviceDiscovery
;
Future
<
List
<
Device
>>
getDevices
(
dynamic
args
)
{
List
<
Device
>
devices
=
<
Device
>[];
devices
.
addAll
(
_androidDeviceDiscovery
.
getDevices
());
return
new
Future
.
value
(
devices
);
}
void
dispose
()
{
_androidDeviceDiscovery
.
dispose
();
}
}
class
AndroidDeviceDiscovery
{
AndroidDeviceDiscovery
()
{
_initAdb
();
if
(
_adb
!=
null
)
{
_subscription
=
_adb
.
trackDevices
().
listen
(
_handleNewDevices
);
}
}
Adb
_adb
;
StreamSubscription
_subscription
;
Map
<
String
,
AndroidDevice
>
_devices
=
new
Map
<
String
,
AndroidDevice
>();
StreamController
<
Device
>
addedController
=
new
StreamController
<
Device
>.
broadcast
();
StreamController
<
Device
>
removedController
=
new
StreamController
<
Device
>.
broadcast
();
StreamController
<
Device
>
changedController
=
new
StreamController
<
Device
>.
broadcast
();
List
<
Device
>
getDevices
()
=>
_devices
.
values
.
toList
();
Stream
<
Device
>
get
onAdded
=>
addedController
.
stream
;
Stream
<
Device
>
get
onRemoved
=>
removedController
.
stream
;
Stream
<
Device
>
get
onChanged
=>
changedController
.
stream
;
void
_initAdb
()
{
if
(
_adb
==
null
)
{
_adb
=
new
Adb
(
AndroidDevice
.
getAdbPath
());
if
(!
_adb
.
exists
())
_adb
=
null
;
}
}
void
_handleNewDevices
(
List
<
AdbDevice
>
newDevices
)
{
List
<
AndroidDevice
>
currentDevices
=
new
List
.
from
(
getDevices
());
for
(
AdbDevice
device
in
newDevices
)
{
AndroidDevice
androidDevice
=
_devices
[
device
.
id
];
if
(
androidDevice
==
null
)
{
// device added
androidDevice
=
new
AndroidDevice
(
id:
device
.
id
,
productID:
device
.
productID
,
modelID:
device
.
modelID
,
deviceCodeName:
device
.
deviceCodeName
,
connected:
device
.
isAvailable
);
_devices
[
androidDevice
.
id
]
=
androidDevice
;
addedController
.
add
(
androidDevice
);
}
else
{
currentDevices
.
remove
(
androidDevice
);
// check state
if
(
androidDevice
.
isConnected
()
!=
device
.
isAvailable
)
{
androidDevice
.
setConnected
(
device
.
isAvailable
);
changedController
.
add
(
androidDevice
);
}
}
}
// device removed
for
(
AndroidDevice
device
in
currentDevices
)
{
_devices
.
remove
(
device
.
id
);
// I don't know the purpose of this cache or if it's a good idea. We should
// probably have a DeviceManager singleton class to coordinate known devices
// and different device discovery mechanisms.
Device
.
removeFromCache
(
device
.
id
);
removedController
.
add
(
device
);
}
}
void
dispose
()
{
_subscription
?.
cancel
();
}
}
Map
<
String
,
dynamic
>
_deviceToMap
(
Device
device
)
{
return
<
String
,
dynamic
>{
'id'
:
device
.
id
,
'platform'
:
_enumToString
(
device
.
platform
),
'available'
:
device
.
isConnected
()
};
}
/// Take an enum value and get the best string representation of that.
///
/// toString() on enums returns 'EnumType.enumName'.
String
_enumToString
(
dynamic
enumValue
)
{
String
str
=
'
$enumValue
'
;
if
(
str
.
contains
(
'.'
))
return
str
.
substring
(
str
.
indexOf
(
'.'
)
+
1
);
return
str
;
}
dynamic
_toJsonable
(
dynamic
obj
)
{
dynamic
_toJsonable
(
dynamic
obj
)
{
if
(
obj
is
String
||
obj
is
int
||
obj
is
bool
||
obj
is
Map
||
obj
is
List
||
obj
==
null
)
if
(
obj
is
String
||
obj
is
int
||
obj
is
bool
||
obj
is
Map
||
obj
is
List
||
obj
==
null
)
return
obj
;
return
obj
;
if
(
obj
is
Device
)
return
obj
;
return
'
$obj
'
;
return
'
$obj
'
;
}
}
packages/flutter_tools/lib/src/device.dart
View file @
8bb8e1d9
...
@@ -21,8 +21,14 @@ abstract class Device {
...
@@ -21,8 +21,14 @@ abstract class Device {
return
_deviceCache
.
putIfAbsent
(
id
,
()
=>
constructor
(
id
));
return
_deviceCache
.
putIfAbsent
(
id
,
()
=>
constructor
(
id
));
}
}
static
void
removeFromCache
(
String
id
)
{
_deviceCache
.
remove
(
id
);
}
Device
.
_
(
this
.
id
);
Device
.
_
(
this
.
id
);
String
get
name
;
/// Install an app package on the current device
/// Install an app package on the current device
bool
installApp
(
ApplicationPackage
app
);
bool
installApp
(
ApplicationPackage
app
);
...
@@ -532,20 +538,25 @@ class AndroidDevice extends Device {
...
@@ -532,20 +538,25 @@ class AndroidDevice extends Device {
String
modelID
;
String
modelID
;
String
deviceCodeName
;
String
deviceCodeName
;
bool
_connected
;
String
_adbPath
;
String
_adbPath
;
String
get
adbPath
=>
_adbPath
;
String
get
adbPath
=>
_adbPath
;
bool
_hasAdb
=
false
;
bool
_hasAdb
=
false
;
bool
_hasValidAndroid
=
false
;
bool
_hasValidAndroid
=
false
;
factory
AndroidDevice
(
factory
AndroidDevice
({
{
String
id:
null
,
String
id:
null
,
String
productID:
null
,
String
productID:
null
,
String
modelID:
null
,
String
modelID:
null
,
String
deviceCodeName:
null
})
{
String
deviceCodeName:
null
,
bool
connected
})
{
AndroidDevice
device
=
Device
.
_unique
(
id
??
defaultDeviceID
,
(
String
id
)
=>
new
AndroidDevice
.
_
(
id
));
AndroidDevice
device
=
Device
.
_unique
(
id
??
defaultDeviceID
,
(
String
id
)
=>
new
AndroidDevice
.
_
(
id
));
device
.
productID
=
productID
;
device
.
productID
=
productID
;
device
.
modelID
=
modelID
;
device
.
modelID
=
modelID
;
device
.
deviceCodeName
=
deviceCodeName
;
device
.
deviceCodeName
=
deviceCodeName
;
if
(
connected
!=
null
)
device
.
_connected
=
connected
;
return
device
;
return
device
;
}
}
...
@@ -553,7 +564,7 @@ class AndroidDevice extends Device {
...
@@ -553,7 +564,7 @@ class AndroidDevice extends Device {
/// we don't have to rely on the test setup having adb available to it.
/// we don't have to rely on the test setup having adb available to it.
static
List
<
AndroidDevice
>
getAttachedDevices
([
AndroidDevice
mockAndroid
])
{
static
List
<
AndroidDevice
>
getAttachedDevices
([
AndroidDevice
mockAndroid
])
{
List
<
AndroidDevice
>
devices
=
[];
List
<
AndroidDevice
>
devices
=
[];
String
adbPath
=
(
mockAndroid
!=
null
)
?
mockAndroid
.
adbPath
:
_
getAdbPath
();
String
adbPath
=
(
mockAndroid
!=
null
)
?
mockAndroid
.
adbPath
:
getAdbPath
();
try
{
try
{
runCheckedSync
([
adbPath
,
'version'
]);
runCheckedSync
([
adbPath
,
'version'
]);
...
@@ -623,7 +634,7 @@ class AndroidDevice extends Device {
...
@@ -623,7 +634,7 @@ class AndroidDevice extends Device {
}
}
AndroidDevice
.
_
(
id
)
:
super
.
_
(
id
)
{
AndroidDevice
.
_
(
id
)
:
super
.
_
(
id
)
{
_adbPath
=
_
getAdbPath
();
_adbPath
=
getAdbPath
();
_hasAdb
=
_checkForAdb
();
_hasAdb
=
_checkForAdb
();
// Checking for [minApiName] only needs to be done if we are starting an
// Checking for [minApiName] only needs to be done if we are starting an
...
@@ -655,7 +666,7 @@ class AndroidDevice extends Device {
...
@@ -655,7 +666,7 @@ class AndroidDevice extends Device {
}
}
}
}
static
String
_
getAdbPath
()
{
static
String
getAdbPath
()
{
if
(
Platform
.
environment
.
containsKey
(
'ANDROID_HOME'
))
{
if
(
Platform
.
environment
.
containsKey
(
'ANDROID_HOME'
))
{
String
androidHomeDir
=
Platform
.
environment
[
'ANDROID_HOME'
];
String
androidHomeDir
=
Platform
.
environment
[
'ANDROID_HOME'
];
String
adbPath1
=
path
.
join
(
androidHomeDir
,
'sdk'
,
'platform-tools'
,
'adb'
);
String
adbPath1
=
path
.
join
(
androidHomeDir
,
'sdk'
,
'platform-tools'
,
'adb'
);
...
@@ -782,6 +793,8 @@ class AndroidDevice extends Device {
...
@@ -782,6 +793,8 @@ class AndroidDevice extends Device {
return
CryptoUtils
.
bytesToHex
(
sha1
.
close
());
return
CryptoUtils
.
bytesToHex
(
sha1
.
close
());
}
}
String
get
name
=>
modelID
;
@override
@override
bool
isAppInstalled
(
ApplicationPackage
app
)
{
bool
isAppInstalled
(
ApplicationPackage
app
)
{
if
(!
isConnected
())
{
if
(!
isConnected
())
{
...
@@ -992,8 +1005,11 @@ class AndroidDevice extends Device {
...
@@ -992,8 +1005,11 @@ class AndroidDevice extends Device {
return
null
;
return
null
;
}
}
@override
bool
isConnected
()
=>
_connected
!=
null
?
_connected
:
_hasValidAndroid
;
bool
isConnected
()
=>
_hasValidAndroid
;
void
setConnected
(
bool
value
)
{
_connected
=
value
;
}
}
}
class
DeviceStore
{
class
DeviceStore
{
...
...
packages/flutter_tools/test/daemon_test.dart
View file @
8bb8e1d9
...
@@ -26,9 +26,9 @@ defineTests() {
...
@@ -26,9 +26,9 @@ defineTests() {
StreamController
<
Map
>
responses
=
new
StreamController
();
StreamController
<
Map
>
responses
=
new
StreamController
();
daemon
=
new
Daemon
(
daemon
=
new
Daemon
(
commands
.
stream
,
commands
.
stream
,
(
Map
result
)
=>
responses
.
add
(
result
)
(
Map
<
String
,
dynamic
>
result
)
=>
responses
.
add
(
result
)
);
);
commands
.
add
({
'id'
:
0
,
'
event
'
:
'daemon.version'
});
commands
.
add
({
'id'
:
0
,
'
method
'
:
'daemon.version'
});
Map
response
=
await
responses
.
stream
.
first
;
Map
response
=
await
responses
.
stream
.
first
;
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'result'
],
isNotEmpty
);
expect
(
response
[
'result'
],
isNotEmpty
);
...
@@ -40,9 +40,9 @@ defineTests() {
...
@@ -40,9 +40,9 @@ defineTests() {
StreamController
<
Map
>
responses
=
new
StreamController
();
StreamController
<
Map
>
responses
=
new
StreamController
();
daemon
=
new
Daemon
(
daemon
=
new
Daemon
(
commands
.
stream
,
commands
.
stream
,
(
Map
result
)
=>
responses
.
add
(
result
)
(
Map
<
String
,
dynamic
>
result
)
=>
responses
.
add
(
result
)
);
);
commands
.
add
({
'id'
:
0
,
'
event
'
:
'daemon.shutdown'
});
commands
.
add
({
'id'
:
0
,
'
method
'
:
'daemon.shutdown'
});
return
daemon
.
onExit
.
then
((
int
code
)
{
return
daemon
.
onExit
.
then
((
int
code
)
{
expect
(
code
,
0
);
expect
(
code
,
0
);
});
});
...
@@ -56,7 +56,7 @@ defineTests() {
...
@@ -56,7 +56,7 @@ defineTests() {
StreamController
<
Map
>
responses
=
new
StreamController
();
StreamController
<
Map
>
responses
=
new
StreamController
();
daemon
=
new
Daemon
(
daemon
=
new
Daemon
(
commands
.
stream
,
commands
.
stream
,
(
Map
result
)
=>
responses
.
add
(
result
),
(
Map
<
String
,
dynamic
>
result
)
=>
responses
.
add
(
result
),
daemonCommand:
command
daemonCommand:
command
);
);
...
@@ -71,10 +71,23 @@ defineTests() {
...
@@ -71,10 +71,23 @@ defineTests() {
when
(
mockDevices
.
iOSSimulator
.
isConnected
()).
thenReturn
(
false
);
when
(
mockDevices
.
iOSSimulator
.
isConnected
()).
thenReturn
(
false
);
when
(
mockDevices
.
iOSSimulator
.
stopApp
(
any
)).
thenReturn
(
false
);
when
(
mockDevices
.
iOSSimulator
.
stopApp
(
any
)).
thenReturn
(
false
);
commands
.
add
({
'id'
:
0
,
'
event
'
:
'app.stopAll'
});
commands
.
add
({
'id'
:
0
,
'
method
'
:
'app.stopAll'
});
Map
response
=
await
responses
.
stream
.
first
;
Map
response
=
await
responses
.
stream
.
first
;
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'result'
],
true
);
expect
(
response
[
'result'
],
true
);
});
});
test
(
'device.getDevices'
,
()
async
{
StreamController
<
Map
>
commands
=
new
StreamController
();
StreamController
<
Map
>
responses
=
new
StreamController
();
daemon
=
new
Daemon
(
commands
.
stream
,
(
Map
<
String
,
dynamic
>
result
)
=>
responses
.
add
(
result
)
);
commands
.
add
({
'id'
:
0
,
'method'
:
'device.getDevices'
});
Map
response
=
await
responses
.
stream
.
first
;
expect
(
response
[
'id'
],
0
);
expect
(
response
[
'result'
],
isList
);
});
});
});
}
}
packages/flutter_tools/tool/daemon_client.dart
View file @
8bb8e1d9
...
@@ -7,8 +7,15 @@ import 'dart:io';
...
@@ -7,8 +7,15 @@ import 'dart:io';
Process
daemon
;
Process
daemon
;
// To use, start from the console and enter:
// version: print version
// shutdown: terminate the server
// start: start an app
// stopAll: stop any running app
// devices: list devices
main
()
async
{
main
()
async
{
daemon
=
await
Process
.
start
(
'
dart'
,
[
'bin/flutter_tools.dart'
,
'daemon'
]);
daemon
=
await
Process
.
start
(
'
flutter'
,
[
'daemon'
]);
print
(
'daemon process started, pid:
${daemon.pid}
'
);
print
(
'daemon process started, pid:
${daemon.pid}
'
);
daemon
.
stdout
daemon
.
stdout
...
@@ -20,13 +27,15 @@ main() async {
...
@@ -20,13 +27,15 @@ main() async {
stdout
.
write
(
'> '
);
stdout
.
write
(
'> '
);
stdin
.
transform
(
UTF8
.
decoder
).
transform
(
const
LineSplitter
()).
listen
((
String
line
)
{
stdin
.
transform
(
UTF8
.
decoder
).
transform
(
const
LineSplitter
()).
listen
((
String
line
)
{
if
(
line
==
'version'
||
line
==
'v'
)
{
if
(
line
==
'version'
||
line
==
'v'
)
{
_send
({
'
event
'
:
'daemon.version'
});
_send
({
'
method
'
:
'daemon.version'
});
}
else
if
(
line
==
'shutdown'
||
line
==
'q'
)
{
}
else
if
(
line
==
'shutdown'
||
line
==
'q'
)
{
_send
({
'
event
'
:
'daemon.shutdown'
});
_send
({
'
method
'
:
'daemon.shutdown'
});
}
else
if
(
line
==
'start'
)
{
}
else
if
(
line
==
'start'
)
{
_send
({
'
event
'
:
'app.start'
});
_send
({
'
method
'
:
'app.start'
});
}
else
if
(
line
==
'stopAll'
)
{
}
else
if
(
line
==
'stopAll'
)
{
_send
({
'event'
:
'app.stopAll'
});
_send
({
'method'
:
'app.stopAll'
});
}
else
if
(
line
==
'devices'
)
{
_send
({
'method'
:
'device.getDevices'
});
}
else
{
}
else
{
print
(
'command not understood:
${line}
'
);
print
(
'command not understood:
${line}
'
);
}
}
...
...
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