Merge "Initial commit for AT-Factory-Tool"
diff --git a/at-factory-tool/atft.py b/at-factory-tool/atft.py
new file mode 100755
index 0000000..355ba88
--- /dev/null
+++ b/at-factory-tool/atft.py
@@ -0,0 +1,260 @@
+#!/usr/bin/python
+"""Graphical tool for managing the ATFA and AT communication.
+
+This tool allows for easy graphical access to common ATFA commands. It also
+locates Fastboot devices and can initiate communication between the ATFA and
+an Android Things device.
+"""
+import atftman
+import fastboot_exceptions
+import fastbootsh
+import wx
+
+
+class Atft(wx.Frame):
+ """wxpython class to handle all GUI commands for the ATFA.
+
+ Creates the GUI and provides various functions for interacting with an
+ ATFA and an Android Things device.
+
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(Atft, self).__init__(*args, **kwargs)
+
+ self.atft_manager = atftman.AtftManager(fastbootsh.FastbootDevice)
+
+ self.panel = wx.Panel(self)
+ self.menubar = wx.MenuBar()
+ self.app_menu = wx.Menu()
+ self.atfa_menu = wx.Menu()
+ self.space_menu = wx.Menu()
+ self.toolbar = self.CreateToolBar()
+
+ # App Menu Options
+ self.shst = self.app_menu.Append(
+ wx.ID_ANY, 'Show Statusbar', kind=wx.ITEM_CHECK)
+ self.app_menu.Check(self.shst.GetId(), True)
+ self.Bind(wx.EVT_MENU, self.ToggleStatusBar, self.shst)
+
+ self.shtl = self.app_menu.Append(
+ wx.ID_ANY, 'Show Toolbar', kind=wx.ITEM_CHECK)
+ self.app_menu.Check(self.shtl.GetId(), True)
+ self.Bind(wx.EVT_MENU, self.ToggleToolBar, self.shtl)
+
+ app_menu_quit = self.app_menu.Append(wx.ID_EXIT, 'Quit')
+ self.Bind(wx.EVT_MENU, self.OnQuit, app_menu_quit)
+
+ # ATFA Menu Options
+ atfa_menu_listdev = self.atfa_menu.Append(wx.ID_ANY, 'List Devices')
+ self.Bind(wx.EVT_MENU, self.OnListDevices, atfa_menu_listdev)
+
+ atfa_menu_storage = self.atfa_menu.Append(wx.ID_ANY, 'Storage Mode')
+ self.Bind(wx.EVT_MENU, self.OnStorageMode, atfa_menu_storage)
+
+ atfa_menu_reboot = self.atfa_menu.Append(wx.ID_ANY, 'Reboot')
+ self.Bind(wx.EVT_MENU, self.OnReboot, atfa_menu_reboot)
+
+ atfa_menu_shutdown = self.atfa_menu.Append(wx.ID_ANY, 'Shutdown')
+ self.Bind(wx.EVT_MENU, self.OnShutdown, atfa_menu_shutdown)
+
+ # Add Menu items to Menubar
+ self.menubar.Append(self.app_menu, 'Application')
+ self.menubar.Append(self.space_menu, ' ')
+ self.menubar.Append(self.atfa_menu, 'ATFA Device')
+ self.SetMenuBar(self.menubar)
+
+ # Toolbar buttons
+ toolbar_devices = self.toolbar.AddLabelTool(
+ wx.ID_ANY, 'List Devices', wx.Bitmap('toolbar_devices.png'))
+ self.Bind(wx.EVT_TOOL, self.OnListDevices, toolbar_devices)
+ toolbar_storage = self.toolbar.AddLabelTool(
+ wx.ID_ANY, 'Storage Mode', wx.Bitmap('toolbar_storage.png'))
+ self.Bind(wx.EVT_TOOL, self.OnStorageMode, toolbar_storage)
+ toolbar_quit = self.toolbar.AddLabelTool(wx.ID_ANY, 'Quit App',
+ wx.Bitmap('toolbar_exit.png'))
+ self.Bind(wx.EVT_TOOL, self.OnQuit, toolbar_quit)
+ toolbar_reboot = self.toolbar.AddLabelTool(wx.ID_ANY, 'Reboot ATFA',
+ wx.Bitmap('toolbar_reboot.png'))
+ self.Bind(wx.EVT_TOOL, self.OnReboot, toolbar_reboot)
+ toolbar_shutdown = self.toolbar.AddLabelTool(
+ wx.ID_ANY, 'Shutdown ATFA', wx.Bitmap('toolbar_shutdown.png'))
+ self.Bind(wx.EVT_TOOL, self.OnShutdown, toolbar_shutdown)
+
+ self.vbox = wx.BoxSizer(wx.VERTICAL)
+ self.st = wx.StaticLine(self.panel, wx.ID_ANY, style=wx.LI_HORIZONTAL)
+ self.vbox.Add(self.st, 0, wx.ALL | wx.EXPAND, 5)
+
+ # Device Output Title
+ self.dev_title = wx.StaticText(self.panel, wx.ID_ANY, 'Detected Devices')
+ self.dev_title_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.dev_title_sizer.Add(self.dev_title, 0, wx.ALL, 5)
+ self.vbox.Add(self.dev_title_sizer, 0, wx.LEFT)
+
+ # Device Output Window
+ self.devices_output = wx.TextCtrl(
+ self.panel,
+ wx.ID_ANY,
+ size=(500, 100),
+ style=wx.TE_MULTILINE | wx.TE_READONLY)
+ self.vbox.Add(self.devices_output, 0, wx.ALL | wx.EXPAND, 5)
+
+ # Command Output Title
+ self.comm_title = wx.StaticText(self.panel, wx.ID_ANY, 'Command Output')
+ self.comm_title_sizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.comm_title_sizer.Add(self.comm_title, 0, wx.ALL, 5)
+ self.vbox.Add(self.comm_title_sizer, 0, wx.LEFT)
+
+ # Command Output Window
+ self.cmd_output = wx.TextCtrl(
+ self.panel,
+ wx.ID_ANY,
+ size=(500, 500),
+ style=wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL)
+ self.vbox.Add(self.cmd_output, 0, wx.ALL | wx.EXPAND, 5)
+
+ self.panel.SetSizer(self.vbox)
+ self.SetMenuBar(self.menubar)
+ self.toolbar.Realize()
+ self.statusbar = self.CreateStatusBar()
+ self.statusbar.SetStatusText('Ready')
+ self.SetSize((800, 800))
+ self.SetTitle('Google AT-Factory-Tool')
+ self.Center()
+ self.Show(True)
+
+ self.OnListDevices(None)
+
+ def PrintToDeviceWindow(self, text):
+ self.devices_output.WriteText(text)
+ self.devices_output.WriteText('\n')
+
+ def PrintToCmdWindow(self, text):
+ self.ClearCommandWindow()
+ self.cmd_output.WriteText(text)
+ self.cmd_output.WriteText('\n')
+
+ def OnListDevices(self, event=None):
+ if event is not None:
+ event.Skip()
+
+ self.ClearDeviceWindow()
+ try:
+ devices = self.atft_manager.ListDevices()
+
+ if devices['atfa_dev'] is not None:
+ self.PrintToDeviceWindow('[ATFA] ' + devices['atfa_dev'])
+ if devices['target_dev'] is not None:
+ self.PrintToDeviceWindow('[Target] ' + devices['target_dev'])
+ except fastboot_exceptions.DeviceNotFoundException:
+ self.PrintToDeviceWindow('No devices found!')
+ except fastboot_exceptions.FastbootFailure:
+ self.PrintToCmdWindow('Fastboot command failed!')
+ except Exception as e: # pylint: disable=broad-except
+ self.PrintException(e)
+
+ def OnGetSerial(self, event):
+ self.OnListDevices()
+ self.PrintToCmdWindow('Getting ATFA Serial number')
+ try:
+ self.atft_manager.atfa_dev_manager.GetSerial()
+ except fastboot_exceptions.DeviceNotFoundException:
+ self.PrintToCmdWindow("Can't get serial number! No Available ATFA!")
+ except fastboot_exceptions.FastbootFailure:
+ self.PrintToCmdWindow('Fastboot command failed!')
+ except Exception as e: # pylint: disable=broad-except
+ self.PrintException(e)
+
+ def OnNormalMode(self, event):
+ self.OnListDevices()
+ self.PrintToCmdWindow('Switching to Normal Mode')
+ try:
+ self.atft_manager.SwitchNormal()
+ except fastboot_exceptions.DeviceNotFoundException:
+ self.PrintToCmdWindow("Can't switch to Normal Mode! No Available ATFA!")
+ except fastboot_exceptions.FastbootFailure:
+ self.PrintToCmdWindow('Fastboot command failed!')
+ except Exception as e: # pylint: disable=broad-except
+ self.PrintException(e)
+
+ def OnStorageMode(self, event):
+ self.OnListDevices()
+ try:
+ self.PrintToCmdWindow('Switching to Storage Mode for' +
+ self.atft_manager.GetAtfaSerial())
+ self.PrintToCmdWindow(self.atft_manager.
+ atfa_dev_manager.SwitchStorage())
+ except fastboot_exceptions.DeviceNotFoundException:
+ self.PrintToCmdWindow("Can't switch to Storage Mode! No Available ATFA!")
+ except fastboot_exceptions.FastbootFailure:
+ self.PrintToCmdWindow('Fastboot command failed!')
+ except Exception as e: # pylint: disable=broad-except
+ self.PrintException(e)
+
+ def OnReboot(self, event):
+ self.OnListDevices()
+ try:
+ self.PrintToCmdWindow('Rebooting' + self.atft_manager.GetAtfaSerial())
+ self.atft_manager.ataf_dev_manager.Reboot()
+ except fastboot_exceptions.DeviceNotFoundException:
+ self.PrintToCmdWindow("Can't reboot! No Available ATFA!")
+ except fastboot_exceptions.FastbootFailure:
+ self.PrintToCmdWindow('Fastboot command failed!')
+ except Exception as e: # pylint: disable=broad-except
+ self.PrintException(e)
+
+ def OnShutdown(self, event):
+ self.OnListDevices()
+ try:
+ self.PrintToCmdWindow('Shutting down' +
+ self.atft_manager.GetAtfaSerial())
+ self.atft_manager.atfa_dev_manager.Shutdown()
+ except fastboot_exceptions.DeviceNotFoundException:
+ self.PrintToCmdWindow("Can't shutdown! No Available ATFA!")
+ except fastboot_exceptions.FastbootFailure:
+ self.PrintToCmdWindow('Fastboot command failed!')
+ except Exception as e: # pylint: disable=broad-except
+ self.PrintException(e)
+
+ def get_logs(self, event):
+ self.OnListDevices()
+ self.atft_manager.atfa_dev_manager.GetLogs()
+
+ def OnQuit(self, event):
+ self.Close()
+
+ def ToggleStatusBar(self, event):
+ if self.shst.IsChecked():
+ self.statusbar.Show()
+ else:
+ self.statusbar.Hide()
+
+ def ToggleToolBar(self, event):
+ if self.shtl.IsChecked():
+ self.toolbar.Show()
+ else:
+ self.toolbar.Hide()
+
+ def ClearCommandWindow(self):
+ # Clear output.
+ self.cmd_output.SetValue('')
+
+ def ClearDeviceWindow(self):
+ # Clear device list.
+ self.devices_output.SetValue('')
+
+ def PrintException(self, e):
+ self.PrintToCmdWindow(self.atft_manager.FormatException(e))
+
+
+def main():
+ # TODO(matta): Check if there's a atft.py already running and not run again
+ # TODO(matta): Inject current host time into ATFA at startup
+ # TODO(matta): Periodically poll for new fastboot devices?
+ app = wx.App()
+ Atft(None)
+ app.MainLoop()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/at-factory-tool/atftman.py b/at-factory-tool/atftman.py
new file mode 100644
index 0000000..edd4f63
--- /dev/null
+++ b/at-factory-tool/atftman.py
@@ -0,0 +1,200 @@
+#!/usr/bin/python
+"""At-Factory-Tool manager module.
+
+This module provides the logical implementation of the graphical tool
+for managing the ATFA and AT communication.
+"""
+import os
+import tempfile
+import uuid
+
+import fastboot_exceptions
+
+
+class EncryptionAlgorithm(object):
+ ALGORITHM_P256 = 1
+ ALGORITHM_CURVE25519 = 2
+
+
+class AtftManager(object):
+ """The manager to implement ATFA tasks.
+
+ TODO(shan): Support multiple target devices.
+ The target_dev attribute can be extended to a list
+
+ Attributes:
+ atfa_dev: A FastbootDevice object identifying the detected ATFA device.
+ target_dev: A FastbootDevice object identifying the AT device
+ to be provisioned.
+ atfa_dev_manager: An interface to do operation on ATFA device.
+ """
+
+ def __init__(self, fastboot_device_controller):
+ """Initialize attributes and store the supplied fastboot_device_controller.
+
+ Args:
+ fastboot_device_controller:
+ The interface to interact with a fastboot device.
+ """
+ self.atfa_dev = None
+ self.target_dev = None
+ self.atfa_dev_manager = None
+ self._fastboot_device_controller = fastboot_device_controller
+
+ def FormatException(self, e):
+ """Format the exception. Concatenate the exception type with the message.
+
+ Args:
+ e: The exception to be printed.
+ Returns:
+ The exception message.
+ """
+ return '{0}: {1}'.format(e.__class__.__name__, e)
+
+ def ListDevices(self):
+ """Get device list.
+
+ Get the serial number of the ATFA device and the target device.
+ If the device does not exist, the returned serial number would be None.
+
+ Returns:
+ A dictionary of
+ {'atfa_dev': ATFA device serial number,
+ 'target_dev': target device serial number}
+ Raises:
+ DeviceNotFoundException: When no device is found.
+ """
+ # ListDevices returns a list of USBHandles
+ device_serials = self._fastboot_device_controller.ListDevices()
+
+ if not device_serials:
+ self.atfa_dev = None
+ self.target_dev = None
+ raise fastboot_exceptions.DeviceNotFoundException()
+ else:
+ for found_dev_serial in device_serials:
+ if found_dev_serial.startswith('ATFA'):
+ self.atfa_dev = self._fastboot_device_controller(found_dev_serial)
+ self.atfa_dev_manager = AtfaDeviceManager(self.atfa_dev)
+ elif found_dev_serial:
+ self.target_dev = self._fastboot_device_controller(found_dev_serial)
+ if self.atfa_dev is None:
+ atfa_dev_serial = None
+ else:
+ atfa_dev_serial = self.atfa_dev.serial_number
+ if self.target_dev is None:
+ target_dev_serial = None
+ else:
+ target_dev_serial = self.target_dev.serial_number
+ return {'atfa_dev': atfa_dev_serial, 'target_dev': target_dev_serial}
+
+ def GetAtfaSerial(self):
+ """Get the serial number for the ATFA device.
+
+ Returns:
+ The serial number for the ATFA device
+ Raises:
+ DeviceNotFoundException: When the device is not found
+ """
+ self._CheckDevice(self.atfa_dev)
+ return self.atfa_dev.serial_number
+
+ def TransferContent(self, src, dst):
+ """Transfer content from a device to another device.
+
+ Download file from one device and store it into a tmp file.
+ Upload file from the tmp file onto another device.
+
+ Args:
+ src: The source device to be copied from.
+ dst: The destination device to be copied to.
+ """
+ # create a tmp folder
+ tmp_folder = tempfile.mkdtemp()
+ # temperate file name is a UUID based on host ID and current time.
+ tmp_file_name = str(uuid.uuid1())
+ file_path = os.path.join(tmp_folder, tmp_file_name)
+ # pull file to local fs
+ src.Upload(file_path)
+ # push file to fastboot device
+ dst.Download(file_path)
+ # delete the temperate file afterwards
+ if os.path.exists(file_path):
+ os.remove(file_path)
+ # delete the temperate folder afterwards
+ if os.path.exists(tmp_folder):
+ os.rmdir(tmp_folder)
+
+ def _CheckDevice(self, device):
+ """Check if the device is a connected fastboot device.
+
+ Args:
+ device: The device to be checked.
+ Raises:
+ DeviceNotFoundException: When the device is not found
+ """
+ if device is None:
+ raise fastboot_exceptions.DeviceNotFoundException()
+
+
+class AtfaDeviceManager(object):
+ """The class to manager ATFA device related operations.
+
+ """
+
+ def __init__(self, atfa_dev):
+ self.atfa_dev = atfa_dev
+
+ def GetSerial(self):
+ """Issue fastboot command to get serial number for the ATFA device.
+
+ Raises:
+ DeviceNotFoundException: When the device is not found.
+ """
+ self._CheckDevice(self.atfa_dev)
+ self.atfa_dev.Oem('serial')
+
+ def SwitchNormal(self):
+ """Switch the ATFA device to normal mode.
+
+ TODO(matta): Find a way to find and nicely unmount drive from Windows.
+ TODO(matta): Have ATFA detect unmount and switch back to g_ser mode.
+
+ Raises:
+ DeviceNotFoundException: When the device is not found
+ """
+ self._CheckDevice(self.atfa_dev)
+
+ def SwitchStorage(self):
+ """Switch the ATFA device to storage mode.
+
+ Returns:
+ The result for the fastboot command.
+ Raises:
+ DeviceNotFoundException: When the device is not found
+ """
+ self._CheckDevice(self.atfa_dev)
+ return self.atfa_dev.Oem('storage')
+
+ def Reboot(self):
+ """Reboot the ATFA device.
+
+ Raises:
+ DeviceNotFoundException: When the device is not found
+ """
+ self._CheckDevice(self.atfa_dev)
+ self.atfa_dev.Oem('reboot')
+
+ def Shutdown(self):
+ """Shutdown the ATFA device.
+
+ Raises:
+ DeviceNotFoundException: When the device is not found
+ """
+ self._CheckDevice(self.atfa_dev)
+ self.atfa_dev.Oem('shutdown')
+
+ def GetLogs(self):
+ # TODO(matta): Add Fastboot command to copy logs to storage device and
+ # switch to mass storage mode
+ self._CheckDevice(self.atfa_dev)
diff --git a/at-factory-tool/atftman_unittest.py b/at-factory-tool/atftman_unittest.py
new file mode 100644
index 0000000..f68bcfc
--- /dev/null
+++ b/at-factory-tool/atftman_unittest.py
@@ -0,0 +1,123 @@
+"""Unit test for atftman."""
+import unittest
+
+import atftman
+import fastboot_exceptions
+from mock import patch
+
+
+files = []
+
+
+class AtftManTest(unittest.TestCase):
+ ATFA_TEST_SERIAL = 'ATFA_TEST_SERIAL'
+ TEST_TMP_FOLDER = '/tmp/TMPTEST/'
+ TEST_SERIAL = 'TEST_SERIAL'
+ TEST_UUID = 'TEST-UUID'
+
+ class FastbootDeviceTemplate(object):
+
+ @staticmethod
+ def ListDevices():
+ pass
+
+ def __init__(self, serial_number):
+ self.serial_number = serial_number
+
+ def Oem(self, oem_command):
+ pass
+
+ def Upload(self, file_path):
+ pass
+
+ def Download(self, file_path):
+ pass
+
+ def Disconnect(self):
+ pass
+
+ def __del__(self):
+ pass
+
+ def setUp(self):
+ self.atft_manager = atftman.AtftManager(self.FastbootDeviceTemplate)
+
+ # Test AtftManager.ListDevices
+ @patch('atftman.AtfaDeviceManager')
+ @patch('__main__.AtftManTest.FastbootDeviceTemplate.ListDevices')
+ def testListDevicesNormal(self, mock_list_devices, mock_atfa_device_manager):
+ mock_list_devices.return_value = [self.TEST_SERIAL,
+ self.ATFA_TEST_SERIAL]
+ devices = self.atft_manager.ListDevices()
+ self.assertEqual(devices['atfa_dev'], self.ATFA_TEST_SERIAL)
+ self.assertEqual(devices['target_dev'], self.TEST_SERIAL)
+ mock_atfa_device_manager.assert_called()
+
+ @patch('__main__.AtftManTest.FastbootDeviceTemplate.ListDevices')
+ def testListDevicesATFA(self, mock_list_devices):
+ mock_list_devices.return_value = [self.ATFA_TEST_SERIAL]
+ devices = self.atft_manager.ListDevices()
+ self.assertEqual(devices['atfa_dev'], self.ATFA_TEST_SERIAL)
+ self.assertEqual(devices['target_dev'], None)
+
+ @patch('__main__.AtftManTest.FastbootDeviceTemplate.ListDevices')
+ def testListDevicesTarget(self, mock_list_devices):
+ mock_list_devices.return_value = [self.TEST_SERIAL]
+ devices = self.atft_manager.ListDevices()
+ self.assertEqual(devices['atfa_dev'], None)
+ self.assertEqual(devices['target_dev'], self.TEST_SERIAL)
+
+ @patch('__main__.AtftManTest.FastbootDeviceTemplate.ListDevices')
+ def testListDevicesNotFound(self, mock_list_devices):
+ mock_list_devices.return_value = []
+ with self.assertRaises(fastboot_exceptions.DeviceNotFoundException):
+ self.atft_manager.ListDevices()
+
+ # Test AtftManager.TransferContent
+
+ @staticmethod
+ def _AppendFile(file_path):
+ files.append(file_path)
+
+ @staticmethod
+ def _CheckFile(file_path):
+ assert file_path in files
+ return True
+
+ @staticmethod
+ def _RemoveFile(file_path):
+ assert file_path in files
+ files.remove(file_path)
+
+ @patch('os.rmdir')
+ @patch('os.remove')
+ @patch('os.path.exists')
+ @patch('tempfile.mkdtemp')
+ @patch('uuid.uuid1')
+ @patch('__main__.AtftManTest.FastbootDeviceTemplate.Upload')
+ @patch('__main__.AtftManTest.FastbootDeviceTemplate.Download')
+ def testTransferContentNormal(self, mock_download, mock_upload,
+ mock_uuid, mock_create_folder,
+ mock_exists, mock_remove, mock_rmdir):
+ # upload (to fs): create a temporary file
+ mock_upload.side_effect = AtftManTest._AppendFile
+ # download (from fs): check if the temporary file exists
+ mock_download.side_effect = AtftManTest._CheckFile
+ mock_exists.side_effect = AtftManTest._CheckFile
+ # remove: remove the file
+ mock_remove.side_effect = AtftManTest._RemoveFile
+ mock_rmdir.side_effect = AtftManTest._RemoveFile
+ mock_create_folder.return_value = self.TEST_TMP_FOLDER
+ files.append(self.TEST_TMP_FOLDER)
+ mock_uuid.return_value = self.TEST_UUID
+ tmp_path = self.TEST_TMP_FOLDER + self.TEST_UUID
+ src = self.FastbootDeviceTemplate(self.TEST_SERIAL)
+ dst = self.FastbootDeviceTemplate(self.TEST_SERIAL)
+ self.atft_manager.TransferContent(src, dst)
+ src.Upload.assert_called_once_with(tmp_path)
+ src.Download.assert_called_once_with(tmp_path)
+ # we should have no temporary file at the end
+ self.assertTrue(not files)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/at-factory-tool/fastboot_exceptions.py b/at-factory-tool/fastboot_exceptions.py
new file mode 100644
index 0000000..185f43c
--- /dev/null
+++ b/at-factory-tool/fastboot_exceptions.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+"""Exceptions for At-Factory-Tool Manager (atftman).
+"""
+
+
+class DeviceNotFoundException(Exception):
+ pass
+
+
+class NoAlgorithmAvailableException(Exception):
+ pass
+
+
+class FastbootFailure(Exception):
+
+ def __init__(self, msg):
+ Exception.__init__(self)
+ self.msg = msg
+
+ def __str__(self):
+ return self.msg
diff --git a/at-factory-tool/fastbootadb.py b/at-factory-tool/fastbootadb.py
new file mode 100644
index 0000000..aa7f850
--- /dev/null
+++ b/at-factory-tool/fastbootadb.py
@@ -0,0 +1,93 @@
+# !/usr/bin/python
+"""Fastboot Interface Implementation using python adb library.
+
+"""
+from adb import fastboot
+from adb import usb_exceptions
+
+import fastboot_exceptions
+
+
+class FastbootDevice(object):
+ """An abstracted fastboot device object.
+
+ Attributes:
+ serial_number: The serial number of the fastboot device.
+ """
+
+ @staticmethod
+ def ListDevices():
+ """List all fastboot devices.
+
+ Returns:
+ A list of serial numbers for all the fastboot devices.
+ """
+ device_serial_numbers = []
+ try:
+ for device in fastboot.FastbootCommands.Devices():
+ device_serial_numbers.append(device.serial_number)
+ except usb_exceptions.FormatMessageWithArgumentsException as e:
+ raise fastboot_exceptions.FastbootFailure(str(e))
+
+ return device_serial_numbers
+
+ def __init__(self, serial_number):
+ """Initiate the fastboot device object.
+
+ Args:
+ serial_number: The serial number of the fastboot device.
+ Raises:
+ FastbootFailure: If failure happens for fastboot commands.
+ """
+ try:
+ self.serial_number = serial_number
+ self._fastboot_commands = (fastboot.FastbootCommands.ConnectDevice(
+ serial=serial_number))
+ except usb_exceptions.FormatMessageWithArgumentsException as e:
+ raise fastboot_exceptions.FastbootFailure(str(e))
+
+ def Oem(self, oem_command):
+ """Run an OEM command.
+
+ Args:
+ oem_command: The OEM command to run.
+ Returns:
+ The result message for the OEM command.
+ Raises:
+ FastbootFailure: If failure happens during the command.
+ """
+ try:
+ return self._fastboot_commands.Oem(oem_command)
+ except usb_exceptions.FormatMessageWithArgumentsException as e:
+ raise fastboot_exceptions.FastbootFailure(str(e))
+
+ def Upload(self, file_path):
+ """Pulls a file from the fastboot device to the local file system.
+
+ TODO: To be implemented. Currently adb library does not support
+ the stage and get_staged command.
+
+ Args:
+ file_path: The file path of the file system
+ that the remote file would be pulled to.
+ """
+ pass
+
+ def Download(self, file_path):
+ """Push a file from the file system to the fastboot device.
+
+ TODO: To be implemented. Currently adb library does not support
+ the stage and get_staged command.
+
+ Args:
+ file_path: The file path of the file on the local file system
+ that would be pushed to fastboot device.
+ """
+ pass
+
+ def Disconnect(self):
+ """Disconnect from the fastboot device."""
+ self._fastboot_commands.Close()
+
+ def __del__(self):
+ self.Disconnect()
diff --git a/at-factory-tool/fastbootadb_unittest.py b/at-factory-tool/fastbootadb_unittest.py
new file mode 100644
index 0000000..01662ad
--- /dev/null
+++ b/at-factory-tool/fastbootadb_unittest.py
@@ -0,0 +1,106 @@
+"""Unit test for fastboot interface using adb library."""
+import unittest
+
+from adb import usb_exceptions
+import fastboot_exceptions
+import fastbootadb
+from mock import MagicMock
+from mock import patch
+
+
+class FastbootAdbTest(unittest.TestCase):
+ ATFA_TEST_SERIAL = 'ATFA_TEST_SERIAL'
+ TEST_COMMAND = 'COMMAND'
+ TEST_MESSAGE_FAILURE = 'FAIL: TEST MESSAGE'
+ TEST_MESSAGE_SUCCESS = 'OKAY: TEST MESSAGE'
+ TEST_SERIAL = 'TEST_SERIAL'
+
+ def setUp(self):
+ pass
+
+ # Test FastbootDevice.__init__
+ @patch('adb.fastboot.FastbootCommands')
+ def testFastbootDeviceInit(self, mock_fastboot_commands):
+ mock_fastboot_instance = MagicMock()
+ mock_fastboot_commands.ConnectDevice.return_value = mock_fastboot_instance
+ fastboot_device = fastbootadb.FastbootDevice(self.TEST_SERIAL)
+ mock_fastboot_commands.ConnectDevice.assert_called_with(
+ serial=self.TEST_SERIAL)
+ self.assertEqual(fastboot_device._fastboot_commands, mock_fastboot_instance)
+ self.assertEqual(fastboot_device.serial_number, self.TEST_SERIAL)
+ return fastboot_device
+
+ # Test FastbootDevice.disconnect
+ @patch('adb.fastboot.FastbootCommands')
+ def testFastbootDeviceDisconnect(self, mock_fastboot_commands):
+ mock_fastboot_instance = MagicMock()
+ mock_fastboot_commands.ConnectDevice.return_value = mock_fastboot_instance
+ fastboot_device = fastbootadb.FastbootDevice(self.TEST_SERIAL)
+ fastboot_device.Disconnect()
+ mock_fastboot_instance.Close.assert_called()
+
+ # Test FastbootDevice.__del__
+ @patch('adb.fastboot.FastbootCommands')
+ def testFastbootDeviceDestroy(self, mock_fastboot_commands):
+ mock_fastboot_instance = MagicMock()
+ mock_fastboot_commands.ConnectDevice.return_value = mock_fastboot_instance
+ fastboot_device = fastbootadb.FastbootDevice(self.TEST_SERIAL)
+ del fastboot_device
+ mock_fastboot_instance.Close.assert_called()
+
+ # Test FastbootDevice.ListDevices
+ @patch('adb.fastboot.FastbootCommands')
+ def testListDevicesNormal(self, mock_fastboot_commands):
+ mock_atfa_usb_handle = MagicMock()
+ mock_target_usb_handle = MagicMock()
+ mock_atfa_usb_handle.serial_number = self.ATFA_TEST_SERIAL
+ mock_target_usb_handle.serial_number = self.TEST_SERIAL
+ # Should return a generator.
+ mock_fastboot_commands.Devices.return_value = (d for d in
+ [mock_atfa_usb_handle,
+ mock_target_usb_handle])
+ devices = fastbootadb.FastbootDevice.ListDevices()
+ mock_fastboot_commands.Devices.assert_called()
+ self.assertEqual(len(devices), 2)
+ self.assertEqual(devices[0], self.ATFA_TEST_SERIAL)
+ self.assertEqual(devices[1], self.TEST_SERIAL)
+
+ @patch('adb.fastboot.FastbootCommands')
+ def testListDevicesFailure(self, mock_fastboot_commands):
+ test_exception = (usb_exceptions.
+ FormatMessageWithArgumentsException(self.
+ TEST_MESSAGE_FAILURE)
+ )
+ mock_fastboot_commands.Devices.side_effect = test_exception
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ fastbootadb.FastbootDevice.ListDevices()
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+ # Test FastbootDevice.Oem
+ @patch('adb.fastboot.FastbootCommands')
+ def testOemNormal(self, mock_fastboot_commands):
+ mock_fastboot_device = MagicMock()
+ mock_fastboot_commands.ConnectDevice.return_value = mock_fastboot_device
+ mock_fastboot_device.Oem.return_value = self.TEST_MESSAGE_SUCCESS
+ fastboot_device = fastbootadb.FastbootDevice(self.TEST_SERIAL)
+ out = fastboot_device.Oem(self.TEST_COMMAND)
+ mock_fastboot_device.Oem.assert_called_once_with(self.TEST_COMMAND)
+ self.assertEqual(self.TEST_MESSAGE_SUCCESS, out)
+
+ @patch('adb.fastboot.FastbootCommands')
+ def testOemFailure(self, mock_fastboot_commands):
+ test_exception = (usb_exceptions.
+ FormatMessageWithArgumentsException(self.
+ TEST_MESSAGE_FAILURE)
+ )
+ mock_fastboot_device = MagicMock()
+ mock_fastboot_commands.ConnectDevice.return_value = mock_fastboot_device
+ mock_fastboot_device.Oem.side_effect = test_exception
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ fastboot_device = fastbootadb.FastbootDevice(self.TEST_SERIAL)
+ fastboot_device.Oem(self.TEST_COMMAND)
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/at-factory-tool/fastbootsh.py b/at-factory-tool/fastbootsh.py
new file mode 100644
index 0000000..b04b7e8
--- /dev/null
+++ b/at-factory-tool/fastbootsh.py
@@ -0,0 +1,91 @@
+# !/usr/bin/python
+"""Fastboot Interface Implementation using sh library.
+
+"""
+import fastboot_exceptions
+import sh
+
+
+class FastbootDevice(object):
+ """An abstracted fastboot device object.
+
+ Attributes:
+ serial_number: The serial number of the fastboot device.
+ """
+
+ @staticmethod
+ def ListDevices():
+ """List all fastboot devices.
+
+ Returns:
+ A list of serial numbers for all the fastboot devices.
+ """
+ out = sh.fastboot('devices')
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+
+ device_serial_numbers = out.replace('\tfastboot', '').rstrip().split('\n')
+ # filter out empty string
+ return filter(None, device_serial_numbers)
+
+ def __init__(self, serial_number):
+ """Initiate the fastboot device object.
+
+ Args:
+ serial_number: The serial number of the fastboot device.
+ """
+ self.serial_number = serial_number
+
+ def Oem(self, oem_command):
+ """Run an OEM command.
+
+ Args:
+ oem_command: The OEM command to run.
+ Returns:
+ The result message for the OEM command.
+ Raises:
+ FastbootFailure: If failure happens during the command.
+ """
+ out = sh.fastboot('-s', self.serial_number, 'oem', oem_command)
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+ return out
+
+ def Upload(self, file_path):
+ """Pulls a file from the fastboot device to the local file system.
+
+ Args:
+ file_path: The file path of the file system
+ that the remote file would be pulled to.
+ Returns:
+ The output for the fastboot command required.
+ Raises:
+ FastbootFailure: If failure happens during the command.
+ """
+ out = sh.fastboot('-s', self.serial_number, 'get_staged', file_path)
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+ return out
+
+ def Download(self, file_path):
+ """Push a file from the file system to the fastboot device.
+
+ Args:
+ file_path: The file path of the file on the local file system
+ that would be pushed to fastboot device.
+ Returns:
+ The output for the fastboot command required.
+ Raises:
+ FastbootFailure: If failure happens during the command.
+ """
+ out = sh.fastboot('-s', self.serial_number, 'stage', file_path)
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+ return out
+
+ def Disconnect(self):
+ """Disconnect from the fastboot device."""
+ pass
+
+ def __del__(self):
+ self.Disconnect()
diff --git a/at-factory-tool/fastbootsh_unittest.py b/at-factory-tool/fastbootsh_unittest.py
new file mode 100644
index 0000000..1dec0ee
--- /dev/null
+++ b/at-factory-tool/fastbootsh_unittest.py
@@ -0,0 +1,129 @@
+"""Unit test for fastboot interface using sh library."""
+import unittest
+
+import fastboot_exceptions
+import fastbootsh
+from mock import patch
+
+
+class FastbootShTest(unittest.TestCase):
+ ATFA_TEST_SERIAL = 'ATFA_TEST_SERIAL'
+ TEST_MESSAGE_FAILURE = 'FAIL: TEST MESSAGE'
+ TEST_MESSAGE_SUCCESS = 'OKAY: TEST MESSAGE'
+ TEST_SERIAL = 'TEST_SERIAL'
+
+ def setUp(self):
+ pass
+
+ # Test FastbootDevice.ListDevices
+ @patch('sh.fastboot', create=True)
+ def testListDevicesOneDevice(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_SERIAL + '\tfastboot'
+ device_serial_numbers = fastbootsh.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with('devices')
+ self.assertEqual(1, len(device_serial_numbers))
+ self.assertEqual(self.TEST_SERIAL, device_serial_numbers[0])
+
+ @patch('sh.fastboot', create=True)
+ def testListDevicesTwoDevices(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = (self.TEST_SERIAL + '\tfastboot\n' +
+ self.ATFA_TEST_SERIAL + '\tfastboot')
+ device_serial_numbers = fastbootsh.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with('devices')
+ self.assertEqual(2, len(device_serial_numbers))
+ self.assertEqual(self.TEST_SERIAL, device_serial_numbers[0])
+ self.assertEqual(self.ATFA_TEST_SERIAL, device_serial_numbers[1])
+
+ @patch('sh.fastboot', create=True)
+ def testListDevicesMultiDevices(self, mock_fastboot_commands):
+ one_device = self.TEST_SERIAL + '\tfastboot'
+ result = one_device
+ for _ in range(0, 9):
+ result += '\n' + one_device
+ mock_fastboot_commands.return_value = result
+ device_serial_numbers = fastbootsh.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with('devices')
+ self.assertEqual(10, len(device_serial_numbers))
+
+ @patch('sh.fastboot', create=True)
+ def testListDevicesNone(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = ''
+ device_serial_numbers = fastbootsh.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with('devices')
+ self.assertEqual(0, len(device_serial_numbers))
+
+ @patch('sh.fastboot', create=True)
+ def testListDevicesFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ fastbootsh.FastbootDevice.ListDevices()
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+ # Test FastbootDevice.Oem
+ @patch('sh.fastboot', create=True)
+ def testOem(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_SUCCESS
+ command = 'TEST COMMAND'
+ device = fastbootsh.FastbootDevice(self.TEST_SERIAL)
+ message = device.Oem(command)
+ mock_fastboot_commands.assert_called_once_with('-s',
+ self.TEST_SERIAL,
+ 'oem',
+ command)
+ self.assertEqual(self.TEST_MESSAGE_SUCCESS, message)
+
+ @patch('sh.fastboot', create=True)
+ def testOemFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ command = 'TEST COMMAND'
+ device = fastbootsh.FastbootDevice(self.TEST_SERIAL)
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ device.Oem(command)
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+ # Test FastbootDevice.Upload
+ @patch('sh.fastboot', create=True)
+ def testUpload(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_SUCCESS
+ command = 'TEST COMMAND'
+ device = fastbootsh.FastbootDevice(self.TEST_SERIAL)
+ message = device.Upload(command)
+ mock_fastboot_commands.assert_called_once_with('-s',
+ self.TEST_SERIAL,
+ 'get_staged',
+ command)
+ self.assertEqual(self.TEST_MESSAGE_SUCCESS, message)
+
+ @patch('sh.fastboot', create=True)
+ def testUploadFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ command = 'TEST COMMAND'
+ device = fastbootsh.FastbootDevice(self.TEST_SERIAL)
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ device.Upload(command)
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+ # Test FastbootDevice.Download
+ @patch('sh.fastboot', create=True)
+ def testDownload(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_SUCCESS
+ command = 'TEST COMMAND'
+ device = fastbootsh.FastbootDevice(self.TEST_SERIAL)
+ message = device.Download(command)
+ mock_fastboot_commands.assert_called_once_with('-s',
+ self.TEST_SERIAL,
+ 'stage',
+ command)
+ self.assertEqual(self.TEST_MESSAGE_SUCCESS, message)
+
+ @patch('sh.fastboot', create=True)
+ def testDownloadFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ command = 'TEST COMMAND'
+ device = fastbootsh.FastbootDevice(self.TEST_SERIAL)
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ device.Download(command)
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/at-factory-tool/fastbootsubp.py b/at-factory-tool/fastbootsubp.py
new file mode 100644
index 0000000..60dd6cf
--- /dev/null
+++ b/at-factory-tool/fastbootsubp.py
@@ -0,0 +1,94 @@
+# !/usr/bin/python
+"""Fastboot Interface Implementation using sh library.
+
+"""
+import subprocess
+import fastboot_exceptions
+
+
+class FastbootDevice(object):
+ """An abstracted fastboot device object.
+
+ Attributes:
+ serial_number: The serial number of the fastboot device.
+ """
+
+ @staticmethod
+ def ListDevices():
+ """List all fastboot devices.
+
+ Returns:
+ A list of serial numbers for all the fastboot devices.
+ """
+ out = subprocess.check_output(['fastboot', 'devices'])
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+
+ device_serial_numbers = out.replace('\tfastboot', '').rstrip().split('\n')
+ # filter out empty string
+ return filter(None, device_serial_numbers)
+
+ def __init__(self, serial_number):
+ """Initiate the fastboot device object.
+
+ Args:
+ serial_number: The serial number of the fastboot device.
+ """
+ self.serial_number = serial_number
+
+ def Oem(self, oem_command):
+ """Run an OEM command.
+
+ Args:
+ oem_command: The OEM command to run.
+ Returns:
+ The result message for the OEM command.
+ Raises:
+ FastbootFailure: If failure happens during the command.
+ """
+ out = subprocess.check_output(['fastboot', '-s', self.serial_number,
+ 'oem', oem_command])
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+ return out
+
+ def Upload(self, file_path):
+ """Pulls a file from the fastboot device to the local file system.
+
+ Args:
+ file_path: The file path of the file system
+ that the remote file would be pulled to.
+ Returns:
+ The output for the fastboot command required.
+ Raises:
+ FastbootFailure: If failure happens during the command.
+ """
+ out = subprocess.check_output(['fastboot', '-s', self.serial_number,
+ 'get_staged', file_path])
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+ return out
+
+ def Download(self, file_path):
+ """Push a file from the file system to the fastboot device.
+
+ Args:
+ file_path: The file path of the file on the local file system
+ that would be pushed to fastboot device.
+ Returns:
+ The output for the fastboot command required.
+ Raises:
+ FastbootFailure: If failure happens during the command.
+ """
+ out = subprocess.check_output(['fastboot', '-s', self.serial_number,
+ 'stage', file_path])
+ if out.startswith('FAIL'):
+ raise fastboot_exceptions.FastbootFailure(out)
+ return out
+
+ def Disconnect(self):
+ """Disconnect from the fastboot device."""
+ pass
+
+ def __del__(self):
+ self.Disconnect()
diff --git a/at-factory-tool/fastbootsubp_unittest.py b/at-factory-tool/fastbootsubp_unittest.py
new file mode 100644
index 0000000..10ca2cf
--- /dev/null
+++ b/at-factory-tool/fastbootsubp_unittest.py
@@ -0,0 +1,129 @@
+"""Unit test for fastboot interface using sh library."""
+import unittest
+
+import fastboot_exceptions
+import fastbootsubp
+from mock import patch
+
+
+class FastbootSubpTest(unittest.TestCase):
+ ATFA_TEST_SERIAL = 'ATFA_TEST_SERIAL'
+ TEST_MESSAGE_FAILURE = 'FAIL: TEST MESSAGE'
+ TEST_MESSAGE_SUCCESS = 'OKAY: TEST MESSAGE'
+ TEST_SERIAL = 'TEST_SERIAL'
+
+ def setUp(self):
+ pass
+
+ # Test FastbootDevice.ListDevices
+ @patch('subprocess.check_output', create=True)
+ def testListDevicesOneDevice(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_SERIAL + '\tfastboot'
+ device_serial_numbers = fastbootsubp.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with(['fastboot', 'devices'])
+ self.assertEqual(1, len(device_serial_numbers))
+ self.assertEqual(self.TEST_SERIAL, device_serial_numbers[0])
+
+ @patch('subprocess.check_output', create=True)
+ def testListDevicesTwoDevices(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = (self.TEST_SERIAL + '\tfastboot\n' +
+ self.ATFA_TEST_SERIAL + '\tfastboot')
+ device_serial_numbers = fastbootsubp.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with(['fastboot', 'devices'])
+ self.assertEqual(2, len(device_serial_numbers))
+ self.assertEqual(self.TEST_SERIAL, device_serial_numbers[0])
+ self.assertEqual(self.ATFA_TEST_SERIAL, device_serial_numbers[1])
+
+ @patch('subprocess.check_output', create=True)
+ def testListDevicesMultiDevices(self, mock_fastboot_commands):
+ one_device = self.TEST_SERIAL + '\tfastboot'
+ result = one_device
+ for _ in range(0, 9):
+ result += '\n' + one_device
+ mock_fastboot_commands.return_value = result
+ device_serial_numbers = fastbootsubp.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with(['fastboot', 'devices'])
+ self.assertEqual(10, len(device_serial_numbers))
+
+ @patch('subprocess.check_output', create=True)
+ def testListDevicesNone(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = ''
+ device_serial_numbers = fastbootsubp.FastbootDevice.ListDevices()
+ mock_fastboot_commands.assert_called_once_with(['fastboot', 'devices'])
+ self.assertEqual(0, len(device_serial_numbers))
+
+ @patch('subprocess.check_output', create=True)
+ def testListDevicesFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ fastbootsubp.FastbootDevice.ListDevices()
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+ # Test FastbootDevice.Oem
+ @patch('subprocess.check_output', create=True)
+ def testOem(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_SUCCESS
+ command = 'TEST COMMAND'
+ device = fastbootsubp.FastbootDevice(self.TEST_SERIAL)
+ message = device.Oem(command)
+ mock_fastboot_commands.assert_called_once_with(['fastboot', '-s',
+ self.TEST_SERIAL,
+ 'oem',
+ command])
+ self.assertEqual(self.TEST_MESSAGE_SUCCESS, message)
+
+ @patch('subprocess.check_output', create=True)
+ def testOemFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ command = 'TEST COMMAND'
+ device = fastbootsubp.FastbootDevice(self.TEST_SERIAL)
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ device.Oem(command)
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+ # Test FastbootDevice.Upload
+ @patch('subprocess.check_output', create=True)
+ def testUpload(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_SUCCESS
+ command = 'TEST COMMAND'
+ device = fastbootsubp.FastbootDevice(self.TEST_SERIAL)
+ message = device.Upload(command)
+ mock_fastboot_commands.assert_called_once_with(['fastboot', '-s',
+ self.TEST_SERIAL,
+ 'get_staged',
+ command])
+ self.assertEqual(self.TEST_MESSAGE_SUCCESS, message)
+
+ @patch('subprocess.check_output', create=True)
+ def testUploadFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ command = 'TEST COMMAND'
+ device = fastbootsubp.FastbootDevice(self.TEST_SERIAL)
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ device.Upload(command)
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+ # Test FastbootDevice.Download
+ @patch('subprocess.check_output', create=True)
+ def testDownload(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_SUCCESS
+ command = 'TEST COMMAND'
+ device = fastbootsubp.FastbootDevice(self.TEST_SERIAL)
+ message = device.Download(command)
+ mock_fastboot_commands.assert_called_once_with(['fastboot', '-s',
+ self.TEST_SERIAL,
+ 'stage',
+ command])
+ self.assertEqual(self.TEST_MESSAGE_SUCCESS, message)
+
+ @patch('subprocess.check_output', create=True)
+ def testDownloadFailure(self, mock_fastboot_commands):
+ mock_fastboot_commands.return_value = self.TEST_MESSAGE_FAILURE
+ command = 'TEST COMMAND'
+ device = fastbootsubp.FastbootDevice(self.TEST_SERIAL)
+ with self.assertRaises(fastboot_exceptions.FastbootFailure) as e:
+ device.Download(command)
+ self.assertEqual(self.TEST_MESSAGE_FAILURE, str(e))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/at-factory-tool/toolbar_devices.png b/at-factory-tool/toolbar_devices.png
new file mode 100644
index 0000000..6c2909c
--- /dev/null
+++ b/at-factory-tool/toolbar_devices.png
Binary files differ
diff --git a/at-factory-tool/toolbar_exit.png b/at-factory-tool/toolbar_exit.png
new file mode 100644
index 0000000..949640f
--- /dev/null
+++ b/at-factory-tool/toolbar_exit.png
Binary files differ
diff --git a/at-factory-tool/toolbar_reboot.png b/at-factory-tool/toolbar_reboot.png
new file mode 100644
index 0000000..6ececb2
--- /dev/null
+++ b/at-factory-tool/toolbar_reboot.png
Binary files differ
diff --git a/at-factory-tool/toolbar_shutdown.png b/at-factory-tool/toolbar_shutdown.png
new file mode 100644
index 0000000..468525f
--- /dev/null
+++ b/at-factory-tool/toolbar_shutdown.png
Binary files differ
diff --git a/at-factory-tool/toolbar_storage.png b/at-factory-tool/toolbar_storage.png
new file mode 100644
index 0000000..3ad7f40
--- /dev/null
+++ b/at-factory-tool/toolbar_storage.png
Binary files differ