// 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. import '../base/process.dart'; import '../globals.dart' as globals; import 'fuchsia_device.dart'; // Usage: tiles_ctl <command> // Supported commands: // start // add [--disable-focus] <url> [<args>...] // remove <key> // list // quit /// A simple wrapper around the 'tiles_ctl' tool running on the Fuchsia device. class FuchsiaTilesCtl { /// Finds the key for the app called [appName], or returns -1 if it can't be /// found. static Future<int> findAppKey(FuchsiaDevice device, String appName) async { final FuchsiaTilesCtl tilesCtl = fuchsiaDeviceTools.tilesCtl; final Map<int, String> runningApps = await tilesCtl.list(device); if (runningApps == null) { globals.printTrace('tiles_ctl is not running'); return -1; } for (final MapEntry<int, String> entry in runningApps.entries) { if (entry.value.contains('$appName#meta')) { return entry.key; } } return -1; } /// Ensures that tiles is running on the device. static Future<bool> ensureStarted(FuchsiaDevice device) async { final FuchsiaTilesCtl tilesCtl = fuchsiaDeviceTools.tilesCtl; final Map<int, String> runningApps = await tilesCtl.list(device); if (runningApps == null) { return tilesCtl.start(device); } return true; } /// Instructs 'tiles' to start on the device. /// /// Returns true on success and false on failure. Future<bool> start(FuchsiaDevice device) async { final RunResult result = await device.shell('tiles_ctl start'); return result.exitCode == 0; } /// Returns a mapping of tile keys to app URLs. /// /// Returns an empty mapping if tiles_ctl is running but no apps are running. /// Returns null if tiles_ctl is not running. Future<Map<int, String>> list(FuchsiaDevice device) async { // Output of tiles_ctl list has the format: // Found 1 tiles: // Tile key 1 url fuchsia-pkg://fuchsia.com/stocks#meta/stocks.cmx ... final Map<int, String> tiles = <int, String>{}; final RunResult result = await device.shell('tiles_ctl list'); if (result.exitCode != 0) { return null; } // Look for evidence that tiles_ctl is not running. if (result.stdout.contains("Couldn't find tiles component in realm")) { return null; } // Find lines beginning with 'Tile' for (final String line in result.stdout.split('\n')) { final List<String> words = line.split(' '); if (words.isNotEmpty && words[0] == 'Tile') { final int key = int.tryParse(words[2]); final String url = words[4]; tiles[key] = url; } } return tiles; } /// Instructs tiles on the device to begin running the app at [url] in a new /// tile. /// /// The app is passed the arguments in [args]. Flutter apps receive these /// arguments as arguments to `main()`. [url] should be formatted as a /// Fuchsia-style package URL, e.g.: /// fuchsia-pkg://fuchsia.com/flutter_gallery#meta/flutter_gallery.cmx /// Returns true on success and false on failure. Future<bool> add(FuchsiaDevice device, String url, List<String> args) async { final RunResult result = await device.shell( 'tiles_ctl add $url ${args.join(" ")}'); return result.exitCode == 0; } /// Instructs tiles on the device to remove the app with key [key]. /// /// Returns true on success and false on failure. Future<bool> remove(FuchsiaDevice device, int key) async { final RunResult result = await device.shell('tiles_ctl remove $key'); return result.exitCode == 0; } /// Instructs tiles on the device to quit. /// /// Returns true on success and false on failure. Future<bool> quit(FuchsiaDevice device) async { final RunResult result = await device.shell('tiles_ctl quit'); return result.exitCode == 0; } }