Add device category, ephemeral, platformType for daemon (#33990)

diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index f8003c3..2bba099 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -72,7 +72,12 @@
     this.productID,
     this.modelID,
     this.deviceCodeName,
-  }) : super(id);
+  }) : super(
+      id,
+      category: Category.mobile,
+      platformType: PlatformType.android,
+      ephemeral: true,
+  );
 
   final String productID;
   final String modelID;
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index 78f582c..708bddf 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -26,7 +26,7 @@
 import '../runner/flutter_command.dart';
 import '../vmservice.dart';
 
-const String protocolVersion = '0.5.0';
+const String protocolVersion = '0.5.1';
 
 /// 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
@@ -659,7 +659,12 @@
   _DeviceEventHandler _onDeviceEvent(String eventName) {
     return (Device device) {
       _serializeDeviceEvents = _serializeDeviceEvents.then<void>((_) async {
-        sendEvent(eventName, await _deviceToMap(device));
+        try {
+          final Map<String, Object> response = await _deviceToMap(device);
+          sendEvent(eventName, response);
+        } catch (err) {
+          printError(err);
+        }
       });
     };
   }
@@ -768,6 +773,9 @@
     'name': device.name,
     'platform': getNameForTargetPlatform(await device.targetPlatform),
     'emulator': await device.isLocalEmulator,
+    'category': device.category?.toString(),
+    'platformType': device.platformType?.toString(),
+    'ephemeral': device.ephemeral,
   };
 }
 
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 3947ce3..14dd869 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -5,6 +5,8 @@
 import 'dart:async';
 import 'dart:math' as math;
 
+import 'package:meta/meta.dart';
+
 import 'android/android_device.dart';
 import 'application_package.dart';
 import 'artifacts.dart';
@@ -28,6 +30,38 @@
 
 DeviceManager get deviceManager => context.get<DeviceManager>();
 
+/// A description of the kind of workflow the device supports.
+class Category {
+  const Category._(this.value);
+
+  static const Category web = Category._('web');
+  static const Category desktop = Category._('desktop');
+  static const Category mobile = Category._('mobile');
+
+  final String value;
+
+  @override
+  String toString() => value;
+}
+
+/// The platform sub-folder that a device type supports.
+class PlatformType {
+  const PlatformType._(this.value);
+
+  static const PlatformType web = PlatformType._('web');
+  static const PlatformType android = PlatformType._('android');
+  static const PlatformType ios = PlatformType._('ios');
+  static const PlatformType linux = PlatformType._('linux');
+  static const PlatformType macos = PlatformType._('macos');
+  static const PlatformType windows = PlatformType._('windows');
+  static const PlatformType fuchsia = PlatformType._('fuchsia');
+
+  final String value;
+
+  @override
+  String toString() => value;
+}
+
 /// A class to get all available devices.
 class DeviceManager {
 
@@ -208,10 +242,19 @@
 
 abstract class Device {
 
-  Device(this.id);
+  Device(this.id, {@required this.category, @required this.platformType, @required this.ephemeral});
 
   final String id;
 
+  /// The [Category] for this device type.
+  final Category category;
+
+  /// The [PlatformType] for this device.
+  final PlatformType platformType;
+
+  /// Whether this is an ephemeral device.
+  final bool ephemeral;
+
   String get name;
 
   bool get supportsStartPaused => true;
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
index df1840e..8576789 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
@@ -175,7 +175,12 @@
 }
 
 class FuchsiaDevice extends Device {
-  FuchsiaDevice(String id, {this.name}) : super(id);
+  FuchsiaDevice(String id, {this.name}) : super(
+      id,
+      platformType: PlatformType.fuchsia,
+      category: null,
+      ephemeral: false,
+  );
 
   @override
   bool get supportsHotReload => true;
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 15f2a2e..6c8d297 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -114,7 +114,12 @@
 class IOSDevice extends Device {
   IOSDevice(String id, { this.name, String sdkVersion })
       : _sdkVersion = sdkVersion,
-        super(id) {
+        super(
+          id,
+          category: Category.mobile,
+          platformType: PlatformType.ios,
+          ephemeral: true,
+      ) {
     _installerPath = _checkForCommand('ideviceinstaller');
     _iproxyPath = _checkForCommand('iproxy');
   }
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index b22e32d..06116b5 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -50,7 +50,7 @@
       return <IOSSimulator>[];
 
     return SimControl.instance.getConnectedDevices().map<IOSSimulator>((SimDevice device) {
-      return IOSSimulator(device.udid, name: device.name, category: device.category);
+      return IOSSimulator(device.udid, name: device.name, simulatorCategory: device.category);
     }).toList();
   }
 }
@@ -215,12 +215,17 @@
 }
 
 class IOSSimulator extends Device {
-  IOSSimulator(String id, { this.name, this.category }) : super(id);
+  IOSSimulator(String id, { this.name, this.simulatorCategory }) : super(
+      id,
+      category: Category.mobile,
+      platformType: PlatformType.ios,
+      ephemeral: true,
+  );
 
   @override
   final String name;
 
-  final String category;
+  final String simulatorCategory;
 
   @override
   Future<bool> get isLocalEmulator async => true;
@@ -435,7 +440,7 @@
   Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;
 
   @override
-  Future<String> get sdkNameAndVersion async => category;
+  Future<String> get sdkNameAndVersion async => simulatorCategory;
 
   final RegExp _iosSdkRegExp = RegExp(r'iOS( |-)(\d+)');
 
diff --git a/packages/flutter_tools/lib/src/linux/linux_device.dart b/packages/flutter_tools/lib/src/linux/linux_device.dart
index 7519737..6f4c49b 100644
--- a/packages/flutter_tools/lib/src/linux/linux_device.dart
+++ b/packages/flutter_tools/lib/src/linux/linux_device.dart
@@ -19,7 +19,12 @@
 
 /// A device that represents a desktop Linux target.
 class LinuxDevice extends Device {
-  LinuxDevice() : super('Linux');
+  LinuxDevice() : super(
+      'Linux',
+      category: Category.desktop,
+      platformType: PlatformType.linux,
+      ephemeral: false,
+  );
 
   @override
   void clearLogs() { }
diff --git a/packages/flutter_tools/lib/src/macos/macos_device.dart b/packages/flutter_tools/lib/src/macos/macos_device.dart
index bf9a307..a082bf0 100644
--- a/packages/flutter_tools/lib/src/macos/macos_device.dart
+++ b/packages/flutter_tools/lib/src/macos/macos_device.dart
@@ -20,7 +20,12 @@
 
 /// A device that represents a desktop MacOS target.
 class MacOSDevice extends Device {
-  MacOSDevice() : super('macOS');
+  MacOSDevice() : super(
+      'macOS',
+      category: Category.desktop,
+      platformType: PlatformType.macos,
+      ephemeral: false,
+  );
 
   @override
   void clearLogs() { }
diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
index 3705057..a7abcf1 100644
--- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart
+++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart
@@ -42,7 +42,12 @@
 
 // TODO(scheglov): This device does not currently work with full restarts.
 class FlutterTesterDevice extends Device {
-  FlutterTesterDevice(String deviceId) : super(deviceId);
+  FlutterTesterDevice(String deviceId) : super(
+      deviceId,
+      platformType: null,
+      category: null,
+      ephemeral: false,
+  );
 
   Process _process;
   final DevicePortForwarder _portForwarder = _NoopPortForwarder();
diff --git a/packages/flutter_tools/lib/src/web/web_device.dart b/packages/flutter_tools/lib/src/web/web_device.dart
index 8238690f..a98e91f 100644
--- a/packages/flutter_tools/lib/src/web/web_device.dart
+++ b/packages/flutter_tools/lib/src/web/web_device.dart
@@ -28,7 +28,12 @@
 }
 
 class WebDevice extends Device {
-  WebDevice() : super('web');
+  WebDevice() : super(
+      'web',
+      category: Category.web,
+      platformType: PlatformType.web,
+      ephemeral: false,
+  );
 
   @override
   bool get supportsHotReload => true;
diff --git a/packages/flutter_tools/lib/src/windows/windows_device.dart b/packages/flutter_tools/lib/src/windows/windows_device.dart
index 103a731..86d80ee 100644
--- a/packages/flutter_tools/lib/src/windows/windows_device.dart
+++ b/packages/flutter_tools/lib/src/windows/windows_device.dart
@@ -21,7 +21,12 @@
 
 /// A device that represents a desktop Windows target.
 class WindowsDevice extends Device {
-  WindowsDevice() : super('Windows');
+  WindowsDevice() : super(
+      'Windows',
+      category: Category.desktop,
+      platformType: PlatformType.windows,
+      ephemeral: false,
+  );
 
   @override
   void clearLogs() { }