Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.cts;
     18 
     19 import com.android.cts.TestHost.ActionType;
     20 import com.android.cts.TestHost.MODE;
     21 
     22 import org.xml.sax.SAXException;
     23 
     24 import java.io.BufferedReader;
     25 import java.io.File;
     26 import java.io.FileNotFoundException;
     27 import java.io.IOException;
     28 import java.io.InputStreamReader;
     29 import java.security.NoSuchAlgorithmException;
     30 import java.util.ArrayList;
     31 import java.util.Collection;
     32 import java.util.HashMap;
     33 import java.util.List;
     34 
     35 import javax.xml.parsers.ParserConfigurationException;
     36 import javax.xml.transform.TransformerException;
     37 import javax.xml.transform.TransformerFactoryConfigurationError;
     38 
     39 /**
     40  * Main console of CTS providing user with the interface to interact. <BR>
     41  * Using CommandParser to parse command line argument and process.
     42  * <ul>
     43  *    <li> start a test plan
     44  *    <li> remove a test plan
     45  *    <li> add a test package
     46  *    <li> remove a test package
     47  *    <li> list current available devices
     48  *    <li> list current available test plan
     49  *    <li> list current available package
     50  *    <li> list current test result
     51  *    <li> view CTS' status, uninitialized, idle or running
     52  *    <li> view command history
     53  *    <li> select a history command to run
     54  * </ul>
     55  */
     56 public class ConsoleUi {
     57 
     58     private static final String OS_NAME_LINUX = "Linux";
     59     private static final String LS_PLAN_SEPARATOR = "=================================";
     60     private static final String CMD_TYPE_LEADING_SPACE = "  ";
     61     private static final String CMD_OPT_LEADING_SPACE = "    ";
     62     private static final String CREATE_SESSION = "create a new session";
     63     private static final String CHOOSE_SESSION = "choose a session";
     64 
     65     private TestHost mHost;
     66     private boolean mKeepRunning;
     67     private BufferedReader mCommandInput;
     68     // private static ConsoleInputStream sConsoleReader;
     69     private CommandHistory mCommandHistory = new CommandHistory();
     70     private String mOsName = "none";
     71 
     72     // Define test case name pattern
     73     static final String CASE_NAME_PATTERN_STR = "((\\S+\\.)+\\S+)\\.(\\S+):(\\S+)";
     74     private static HashMap<String, Integer> mResultCodeMap;
     75 
     76     static {
     77         mResultCodeMap = new HashMap<String, Integer>();
     78         mResultCodeMap.put(CtsTestResult.STR_PASS, CtsTestResult.CODE_PASS);
     79         mResultCodeMap.put(CtsTestResult.STR_FAIL, CtsTestResult.CODE_FAIL);
     80         mResultCodeMap.put(CtsTestResult.STR_ERROR, CtsTestResult.CODE_ERROR);
     81         mResultCodeMap.put(CtsTestResult.STR_NOT_EXECUTED, CtsTestResult.CODE_NOT_EXECUTED);
     82         mResultCodeMap.put(CtsTestResult.STR_TIMEOUT, CtsTestResult.CODE_TIMEOUT);
     83     }
     84 
     85     public ConsoleUi(TestHost host) {
     86         mHost = host;
     87         mCommandInput = new BufferedReader(new InputStreamReader(System.in));
     88         mKeepRunning = true;
     89 
     90         initInputStream();
     91     }
     92 
     93     /**
     94      * Start the console user interface.
     95      *
     96      */
     97     public void startUi() {
     98         while (mKeepRunning) {
     99             try {
    100                 String cmdLine = readLine(CUIOutputStream.CTS_PROMPT_SIGN);
    101                 CommandParser cp = CommandParser.parse(cmdLine);
    102                 processCommand(cp);
    103                 mCommandHistory.addCommand(cp, cmdLine);
    104             } catch (CommandNotFoundException e) {
    105                 // avoid displaying help message for empty
    106                 // command by pressing ENTER over console directly
    107             } catch (Exception e) {
    108                 Log.e("Got exception while processing command.", e);
    109                 showHelp();
    110             }
    111         }
    112     }
    113 
    114     /**
    115      * Initialize the CommandProcessor.
    116      */
    117     private void initInputStream() {
    118         // mOsName = System.getProperty("os.name");
    119         if (mOsName.equals(OS_NAME_LINUX)) {
    120             // sConsoleReader = new ConsoleInputStream(new FileInputStream(
    121             // FileDescriptor.in), mCommandHistory);
    122             // sConsoleReader.setup();
    123         } else {
    124             mCommandInput = new BufferedReader(new InputStreamReader(System.in));
    125         }
    126     }
    127 
    128     /**
    129      * Read a message line from console.
    130      *
    131      * @param prompt The notification message print out to console before reading.
    132      * @return The string user typed in.
    133      */
    134     private String readLine(String prompt) throws IOException {
    135         String cmdLine = null;
    136         if (mOsName.equals(OS_NAME_LINUX)) {
    137             // cmdLine = sConsoleReader.readLine(prompt).trim();
    138         } else {
    139             CUIOutputStream.print(prompt);
    140             cmdLine = mCommandInput.readLine().trim();
    141         }
    142         return cmdLine;
    143     }
    144 
    145     /**
    146      * Display the help message.
    147      */
    148     private void showHelp() {
    149         CUIOutputStream.println("Usage: command options");
    150         CUIOutputStream.println("Avaiable commands and options:");
    151         showHostCmdHelp();
    152         showPlanCmdHelp();
    153         showPackageCmdHelp();
    154         showResultCmdHelp();
    155         showHistoryCmdHelp();
    156         showDeviceCmdHelp();
    157     }
    158 
    159     /**
    160      * Display the help message related to history commands.
    161      */
    162     private void showHistoryCmdHelp() {
    163         final String cmdStr = CTSCommand.HISTORY + "/" + CTSCommand.H;
    164 
    165         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "History:");
    166         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    167                 + cmdStr + ": list all commands in command history");
    168         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    169                 + cmdStr + " count: list the latest count records in command history");
    170         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    171                 + cmdStr + " " + CTSCommand.OPTION_E
    172                 + " num: run the command designated by 'num' in command history");
    173     }
    174 
    175     /**
    176      * Display the help message related to result commands.
    177      */
    178     private void showResultCmdHelp() {
    179         final String cmdStr = CTSCommand.LIST + " " + CTSCommand.OPTION_R
    180                 + "/" + CTSCommand.OPTION_RESULT;
    181         final String sessionStr = CTSCommand.OPTION_S + "/" + CTSCommand.OPTION_SESSION;
    182         final String resultsStr = " [" + CtsTestResult.STR_PASS
    183                        + "/" + CtsTestResult.STR_FAIL
    184                        + "/" + CtsTestResult.STR_NOT_EXECUTED
    185                        + "/" + CtsTestResult.STR_TIMEOUT
    186                        + "] ";
    187 
    188         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Result:");
    189         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    190                 + cmdStr + ": list all result of sessions");
    191         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    192                 + cmdStr + " " + sessionStr
    193                 + " session_id: list detail case result of a specified session");
    194         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    195                 + cmdStr + resultsStr + sessionStr
    196                 + " session_id: list detail cases of a specified"
    197                 + " session by the specified result.");
    198     }
    199 
    200     /**
    201      * Display the help message related to package commands.
    202      */
    203     private void showPackageCmdHelp() {
    204         final String cmdStr = CTSCommand.LIST + " " + CTSCommand.OPTION_P
    205                 + "/" + CTSCommand.OPTION_PACKAGE;
    206         final String pkgStr = CTSCommand.OPTION_P + "/" + CTSCommand.OPTION_PACKAGE;
    207 
    208         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Package:");
    209         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    210                 + cmdStr + ": list available packages");
    211         CUIOutputStream.println(CMD_OPT_LEADING_SPACE + cmdStr + " package_name: "
    212                 + "list contents of the package with specified name");
    213 
    214         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    215                 + CTSCommand.ADD + " " + pkgStr
    216                 + " root: add packages from root to repository");
    217         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    218                 + CTSCommand.REMOVE + " " + pkgStr + " package_name/all: "
    219                 + "remove a package or all packages from repository");
    220     }
    221 
    222     /**
    223      * Display the help message related to plan commands.
    224      */
    225     private void showPlanCmdHelp() {
    226         final String lsPlanStr = CTSCommand.LIST + " " + CTSCommand.OPTION_PLAN;
    227         final String addPlanStr = CTSCommand.ADD + " " + CTSCommand.OPTION_PLAN;
    228         final String rmPlanStr = CTSCommand.REMOVE + " " + CTSCommand.OPTION_PLAN;
    229         final String addDerivedPlanStr = CTSCommand.ADD + " " + CTSCommand.OPTION_DERIVED_PLAN;
    230 
    231         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Plan:");
    232         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    233                 + lsPlanStr + ": list available plans");
    234         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    235                 + lsPlanStr + " plan_name: list contents of the plan with specified name");
    236         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    237                 + addPlanStr + " plan_name: add a new plan with specified name");
    238         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    239                 + addDerivedPlanStr + " plan_name "
    240                 + CTSCommand.OPTION_S + "/" + CTSCommand.OPTION_SESSION + " session_id "
    241                 + CTSCommand.OPTION_R + "/" + CTSCommand.OPTION_RESULT + " result_type"
    242                 + ": derive a plan from the given session");
    243         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    244                 + rmPlanStr + " plan_name/all: remove a plan or all plans from repository");
    245         showStartSessionHelp();
    246     }
    247 
    248     /**
    249      * Display the help message related to start session command.
    250      */
    251     private void showStartSessionHelp() {
    252         final String cmdStr = CTSCommand.START + " " + CTSCommand.OPTION_PLAN;
    253         final String testStr = CTSCommand.OPTION_T + "/" + CTSCommand.OPTION_TEST;
    254         final String deviceStr = CTSCommand.OPTION_D + "/" + CTSCommand.OPTION_DEVICE;
    255         final String pkgStr = CTSCommand.OPTION_P + "/" + CTSCommand.OPTION_PACKAGE;
    256 
    257         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    258                 + cmdStr + " test_plan_name: run a test plan");
    259         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    260                 + cmdStr + " test_plan_name " + deviceStr + " device_ID: "
    261                 + "run a test plan using the specified device");
    262         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    263             + cmdStr + " test_plan_name " + testStr + " test_name: run a specific test");
    264         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    265                 + cmdStr + " test_plan_name " + pkgStr + " java_package_name: "
    266                 + "run a specific java package");
    267         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    268                 + cmdStr + " test_plan_name " + testStr + " test_name "
    269                 + deviceStr + " device_ID: run a specific test using the specified device");
    270         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    271                 + cmdStr + " test_plan_name " + pkgStr + " java_package_name "
    272                 + deviceStr + " device_ID: "
    273                 + "run a specific java package using the specified device");
    274     }
    275 
    276     /**
    277      * Display the help message related to host commands.
    278      */
    279     private void showHostCmdHelp() {
    280         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Host:");
    281         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    282                 + CTSCommand.HELP + ": show this message");
    283         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    284                 + CTSCommand.EXIT + ": exit cts command line");
    285     }
    286 
    287     /**
    288      * Display the help message related to device commands.
    289      */
    290     private void showDeviceCmdHelp() {
    291         final String deviceStr = CTSCommand.OPTION_D + "/" + CTSCommand.OPTION_DEVICE;
    292 
    293         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Device:");
    294         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    295                 + CTSCommand.LIST + " " + deviceStr + ": list available devices");
    296     }
    297 
    298     /**
    299      * Process the command from user's input.
    300      *
    301      * @param cp Command container.
    302      */
    303     public void processCommand(final CommandParser cp) throws Exception {
    304         String action = cp.getAction();
    305 
    306         if (action.equals(CTSCommand.EXIT)) {
    307             if (cp.getArgSize() != 1) {
    308                 showHelp();
    309                 return;
    310             }
    311             Log.d("exit cts host");
    312             mKeepRunning = false;
    313             mHost.tearDown();
    314         } else if (action.equals(CTSCommand.HELP)) {
    315             showHelp();
    316         } else if (mCommandHistory.isHistoryCommand(action)) {
    317             processHistoryCommands(cp);
    318         } else if (action.equals(CTSCommand.ADD)) {
    319             processAddCommand(cp);
    320         } else if (action.equals(CTSCommand.START)) {
    321             processStartCommand(cp);
    322         } else if (action.equals(CTSCommand.REMOVE)) {
    323             processRmCommand(cp);
    324         } else if (action.equals(CTSCommand.LIST)) {
    325             processListCommand(cp);
    326         } else {
    327             showHelp();
    328         }
    329     }
    330 
    331     /**
    332      * Process start command.
    333      *
    334      * @param cp Command container.
    335      */
    336     private void processStartCommand(CommandParser cp) throws SAXException,
    337             ParserConfigurationException {
    338         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    339             processStartSessionCommand(cp);
    340         } else if (cp.containsKey(CTSCommand.OPTION_P)
    341                 || cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    342             processStartPackageCommand(cp);
    343         } else {
    344             showHelp();
    345         }
    346     }
    347 
    348     /**
    349      * Process start package command.
    350      *
    351      * <ul>
    352      *     <li> Syntax:
    353      *            start --package zipped-package-file
    354      * </ul>
    355      * @param cp Command container.
    356      */
    357     private void processStartPackageCommand(CommandParser cp) {
    358         try {
    359             String pathName = cp.getValue(CTSCommand.OPTION_PACKAGE);
    360             mHost.startZippedPackage(pathName);
    361         } catch (DeviceDisconnectedException e) {
    362           Log.e("Device " + e.getMessage() + " disconnected", e);
    363         } catch (Exception e) {
    364             Log.e("Met exception during running zipped package.", e);
    365         }
    366     }
    367 
    368     /**
    369      * Validate the command parameters used to activate CTS.
    370      *
    371      * @param cp Command container.
    372      * @return If command parameters are valid, return true; else, return false.
    373      */
    374     public boolean validateCommandParams(CommandParser cp) {
    375         if (cp == null) {
    376             return false;
    377         }
    378 
    379         if (cp.getAction() == null) {
    380             return true;
    381         } else if (isValidCommandOption(cp, CTSCommand.START,
    382                 CTSCommand.OPTION_PLAN)) {
    383             return true;
    384         } else if (isValidCommandOption(cp, CTSCommand.START,
    385                 CTSCommand.OPTION_PACKAGE)) {
    386             return true;
    387         } else if (isValidCommandOption(cp, CTSCommand.START,
    388                 CTSCommand.OPTION_P)) {
    389             return true;
    390         } else {
    391             return false;
    392         }
    393     }
    394 
    395     /**
    396      * Check if the command option is valid.
    397      *
    398      * @param cp CommandParser which contains the command and options.
    399      * @param command Command the user typed in.
    400      * @param option Option the user typed in.
    401      * @return If command option valid, return true; else, return false.
    402      */
    403     private static boolean isValidCommandOption(CommandParser cp,
    404             String command, String option) {
    405         return (cp.getAction().equals(command)) && (cp.containsKey(option))
    406                 && (cp.getValue(option) != null)
    407                 && (cp.getValue(option).length() != 0);
    408     }
    409 
    410     /**
    411      * Process start session command.
    412      * <ul>
    413      *     <li> Syntax 1:
    414      *            start --plan plan-name
    415      *              [ --device device-id ]
    416      *              [ --test test-name ]
    417      *     <li> Syntax 2:
    418      *            start --plan plan-name
    419      *              [ --device device-id ]
    420      *              [ --package java-package-name ]
    421      * </ul>
    422      * @param cp container which contained start command options and values
    423      *           Process the list commands.
    424      */
    425     private void processStartSessionCommand(CommandParser cp)
    426             throws SAXException, ParserConfigurationException {
    427 
    428         if (mHost.getDeviceList().length == 0) {
    429             Log.e("No device connected", null);
    430             return;
    431         }
    432 
    433         String testPlanPath = null;
    434         String deviceId = null;
    435         String testName = null;
    436         String javaPkgName = null;
    437         String testPlanName = mHost.getPlanName(cp.getValue(CTSCommand.OPTION_PLAN));
    438         try {
    439             if (cp.getActionValues().size() != 0 || cp.getOptionSize() < 1
    440                     || cp.getOptionSize() > 3) {
    441                 showStartSessionHelp();
    442                 return;
    443             }
    444             testPlanName = mHost.getPlanName(cp
    445                     .getValue(CTSCommand.OPTION_PLAN));
    446             testPlanPath = HostConfig.getInstance().getPlanRepository()
    447                     .getPlanPath(testPlanName);
    448             if (testPlanPath == null) {
    449                 CUIOutputStream.println("Plan " + testPlanName
    450                         + " is not in repository, please create it!");
    451                 return;
    452             }
    453 
    454             if (cp.containsKey(CTSCommand.OPTION_DEVICE)) {
    455                 deviceId = cp.getValue(CTSCommand.OPTION_DEVICE);
    456                 String[] deviceIdList = deviceId.trim().split(",");
    457                 if (deviceIdList.length > 1) {
    458                     Log.e("Just allow choosing one device ID.", null);
    459                     return;
    460                 }
    461             }
    462 
    463             ActionType actionType = ActionType.START_NEW_SESSION;
    464             if (cp.containsKey(CTSCommand.OPTION_TEST)) {
    465                 testName = cp.getValue(CTSCommand.OPTION_TEST);
    466                 if (-1 == testName.indexOf(Test.METHOD_SEPARATOR)) {
    467                     Log.e("Test full name must be in the form of:"
    468                             + " java_package_name.class_name#method_name.", null);
    469                     return;
    470                 }
    471                 actionType = ActionType.RUN_SINGLE_TEST;
    472             } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    473                 javaPkgName = cp.getValue(CTSCommand.OPTION_PACKAGE);
    474                 actionType = ActionType.RUN_SINGLE_JAVA_PACKAGE;
    475             }
    476 
    477             TestSession ts = null;
    478             ArrayList<TestSession> sessionList = mHost.getSessionList(testPlanName);
    479             if ((sessionList != null) && (sessionList.size() > 0)) {
    480                 if ((testName == null) || (testName.length() == 0)) {
    481                     String mode = chooseMode(sessionList);
    482                     if (CREATE_SESSION.equals(mode)) {
    483                         ts = TestHost.createSession(testPlanName);
    484                     }
    485                 }
    486                 if (ts == null) {
    487                     ts = chooseTestSession(sessionList);
    488                     deviceId = ts.getDeviceId();
    489                     if ((actionType != ActionType.RUN_SINGLE_TEST)
    490                             && (actionType != ActionType.RUN_SINGLE_JAVA_PACKAGE)) {
    491                         actionType = ActionType.RESUME_SESSION;
    492                     }
    493                 }
    494             }
    495 
    496             if (deviceId == null) {
    497                 TestDevice td = mHost.getFirstAvailableDevice();
    498                 if (td == null) {
    499                     // no devices attached
    500                     CUIOutputStream.println("No idle devices found.");
    501                     return;
    502                 }
    503                 deviceId = td.getSerialNumber();
    504             }
    505 
    506             if (!checkDeviceExists(mHost.getDeviceList(), deviceId)) {
    507                 CUIOutputStream.println("Can't find specified device id.  Is it attached?");
    508                 return;
    509             }
    510 
    511             if (ts == null) {
    512                 ts = TestHost.createSession(testPlanName);
    513             }
    514             mHost.startSession(ts, deviceId, testName, javaPkgName, actionType);
    515         } catch (IOException e) {
    516             Log.e("Can't create test session", e);
    517         } catch (DeviceNotAvailableException e) {
    518             CUIOutputStream.println("Test plan(" + testPlanName + ") "
    519                     + e.getMessage());
    520             showStartSessionHelp();
    521         } catch (TestNotFoundException e) {
    522             CUIOutputStream.println(e.getMessage());
    523         } catch (TestPlanNotFoundException e) {
    524             CUIOutputStream.println("Can't find test plan " + testPlanName);
    525         } catch (IllegalTestNameException e) {
    526             CUIOutputStream.println("Illegal case name: " + testName);
    527         } catch (DeviceDisconnectedException e) {
    528             Log.e("Device " + e.getMessage() + " disconnected ", null);
    529         } catch (NoSuchAlgorithmException e) {
    530             Log.e("Fail to initialise SHA-1 algorithm", e);
    531         } catch (InvalidApkPathException e) {
    532             Log.e(e.getMessage(), null);
    533         } catch (InvalidNameSpaceException e) {
    534             Log.e(e.getMessage(), null);
    535         }
    536     }
    537 
    538     /**
    539      * Choose test session among the available test session list.
    540      *
    541      * @param sessionList The available test session list.
    542      * @return The test session chosen.
    543      */
    544     private TestSession chooseTestSession(ArrayList<TestSession> sessionList) throws IOException {
    545         if ((sessionList == null) || (sessionList.size() == 0)) {
    546             return null;
    547         }
    548 
    549         if (sessionList.size() == 1) {
    550             return sessionList.get(0);
    551         }
    552 
    553         int index = 0;
    554         String notification = "Please choose a session from the existed session(s):\n";
    555         for (TestSession session : sessionList) {
    556             notification += "  " + session.getId() + "  [" + index + "] \n";
    557             index ++;
    558         }
    559 
    560         return sessionList.get(getUserInputId(notification, 0, index));
    561     }
    562 
    563     /**
    564      * Choose  between creating a new session and choosing a session among available ones.
    565      *
    566      * @param sessionList The available test session list.
    567      * @return If choose to create a new session, return CREATE_SESSION;
    568      *         else return CHOOSE_SESSION.
    569      */
    570     private String chooseMode(ArrayList<TestSession> sessionList) throws IOException {
    571         if (TestHost.sMode == MODE.RUN || (sessionList == null) || (sessionList.size() == 0)) {
    572             // do not prompt if the test run was started from command line mode, or when
    573             // there are no existing sessions
    574             return CREATE_SESSION;
    575         }
    576 
    577         String planName = sessionList.get(0).getSessionLog().getTestPlanName();
    578         String notification = "There are " + sessionList.size()
    579             + " existing session(s) for plan " + planName + ".\n"
    580             + "Create a new session or choose an existing one?\n"
    581             + "  Create a new session [0]\n"
    582             + "  Choose a session     [1]\n";
    583 
    584         int indexSelected = getUserInputId(notification, 0, 2);
    585         if (indexSelected == 0) {
    586             return CREATE_SESSION;
    587         } else {
    588             return CHOOSE_SESSION;
    589         }
    590     }
    591 
    592     /**
    593      * Validate the specified device ID against the available device array.
    594      *
    595      * @param availableDevices The available device array.
    596      * @param specifiedId The specified device ID list.
    597      * @return true if the id is valid
    598      */
    599     public boolean checkDeviceExists(TestDevice[] availableDevices, String specifiedId) {
    600         for (TestDevice dev : availableDevices) {
    601             if (specifiedId.equals(dev.getSerialNumber())) {
    602                 return true;
    603             }
    604         }
    605         return false;
    606     }
    607 
    608     /**
    609      * Get device ID from the device ID string against the available devices.
    610      *
    611      * @param availableDevices The available devices.
    612      * @param idStr The device ID string.
    613      * @return The device ID.
    614      */
    615     public int getDeviceId(TestDevice[] availableDevices, String idStr) {
    616         for (int i = 0; i < availableDevices.length; i++) {
    617             TestDevice dev = availableDevices[i];
    618             if (idStr.equals(dev.getSerialNumber())) {
    619                 return i;
    620             }
    621         }
    622         return -1;
    623     }
    624 
    625     /**
    626      * Get the ID input by the against the specified range.
    627      *
    628      * @param notification The notification message to notify the user.
    629      * @param startIndex The start index.
    630      * @param endIndex The end index.
    631      * @return The selected index of the ID the user chosen.
    632      */
    633     private int getUserInputId(String notification, int startIndex, int endIndex)
    634                 throws IOException {
    635         int indexSelected = 0;
    636         boolean success = false;
    637         while (!success) {
    638             String answer = readLine(notification);
    639             try {
    640                 indexSelected = Integer.parseInt(answer);
    641                 if ((indexSelected >= 0) && (indexSelected < endIndex)) {
    642                     success = true;
    643                 } else {
    644                     CUIOutputStream.println("" + indexSelected
    645                             + " is out of range [0," + (endIndex -1 ) + "].");
    646                 }
    647             } catch (NumberFormatException e) {
    648                 CUIOutputStream.println("Invalid nuber is typed in.");
    649             }
    650         }
    651         return indexSelected;
    652     }
    653 
    654     /**
    655      * Check if the specified device ID is valid.
    656      *
    657      * @param numOfAvailableDevices The number of available devices.
    658      * @param specifiedId The specified device ID.
    659      * @return If the specified ID contained in available ID list,
    660      *         return true; else, return false.
    661      */
    662     public boolean isValidDeviceId(int numOfAvailableDevices, int specifiedId) {
    663         if (specifiedId < 0 || specifiedId >= numOfAvailableDevices) {
    664             return false;
    665         }
    666         return true;
    667     }
    668 
    669     /**
    670      * Process list commands.
    671      * <ul>
    672      *     <li> Syntax 1:
    673      *            ls --device
    674      *     <li> Syntax 2:
    675      *            ls --plan [ plan-name ]
    676      *     <li> Syntax 3:
    677      *            ls --package [ package-name ]
    678      *     <li> Syntax 4:
    679      *            ls --result
    680      *              [ pass/fail/notExecuted/timeout ]
    681      *              [ --session session_id ]
    682      * </ul>
    683      *
    684      * @param cp Command container.
    685      */
    686     private void processListCommand(CommandParser cp) throws SAXException,
    687             IOException, ParserConfigurationException {
    688         if (cp.containsKey(CTSCommand.OPTION_DEVICE)) {
    689             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    690                 showDeviceCmdHelp();
    691                 return;
    692             }
    693             if (cp.getValue(CTSCommand.OPTION_DEVICE).equals("")) {
    694                 listDevices();
    695             } else {
    696                 showDeviceCmdHelp();
    697             }
    698         } else if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    699             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    700                 showPlanCmdHelp();
    701                 return;
    702             }
    703             String planValue = cp.getValue(CTSCommand.OPTION_PLAN);
    704             if (planValue.equals("")) {
    705                 listPlans();
    706             } else {
    707                 listSinglePlan(mHost.getPlanName(planValue));
    708             }
    709         } else if (cp.containsKey(CTSCommand.OPTION_RESULT)) {
    710             if (cp.getActionValues().size() != 0
    711                     || (cp.getOptionSize() < 1 || cp.getOptionSize() > 2)) {
    712                 showResultCmdHelp();
    713                 return;
    714             }
    715             String resultValue = cp.getValue(CTSCommand.OPTION_RESULT);
    716             String sessionId = cp.getValue(CTSCommand.OPTION_SESSION);
    717             Integer resultCode = null;
    718 
    719             if (sessionId != null) {
    720                 if (resultValue.length() != 0
    721                         && !mResultCodeMap.containsKey(resultValue)) {
    722                     showResultCmdHelp();
    723                 } else {
    724                     resultCode = mResultCodeMap.get(resultValue);
    725                     listSessionResult(sessionId, resultCode);
    726                 }
    727             } else if (resultValue.length() == 0) {
    728                 listResults();
    729             } else {
    730                 showHelp();
    731             }
    732         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    733             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    734                 showPackageCmdHelp();
    735                 return;
    736             }
    737             listPackages(cp);
    738         } else {
    739             showHelp();
    740         }
    741     }
    742 
    743     /**
    744      * Process the removing commands.
    745      * <ul>
    746      *     <li> Syntax 1:
    747      *            rm --plan [ plan-name ] [ all ]
    748      *     <li> Syntax 2:
    749      *            rm --package [ package-name ] [ all ]
    750      * </ul>
    751      *
    752      * @param cp Command container.
    753      */
    754     private void processRmCommand(CommandParser cp) throws IOException {
    755         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    756             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    757                 showPlanCmdHelp();
    758                 return;
    759             }
    760 
    761             String planName = mHost.getPlanName(cp.getValue(CTSCommand.OPTION_PLAN));
    762             if (HostConfig.ALL.equals(planName)) {
    763                 String prompt = "Remove all of the plans?([y/N])";
    764                 String answer = readLine(prompt).trim();
    765                 if (!isConfirmation(answer, false)) {
    766                     return;
    767                 }
    768             }
    769 
    770             mHost.removePlans(planName);
    771         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    772             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    773                 showPackageCmdHelp();
    774                 return;
    775             }
    776 
    777             String packageName = cp.getValue(CTSCommand.OPTION_PACKAGE);
    778             if (HostConfig.ALL.equals(packageName)) {
    779                 String prompt = "Remove all of the packages?([y/N])";
    780                 String answer = readLine(prompt).trim();
    781                 if (!isConfirmation(answer, false)) {
    782                     return;
    783                 }
    784             }
    785 
    786             mHost.removePackages(packageName);
    787         } else {
    788             showHelp();
    789         }
    790     }
    791 
    792     /**
    793      * Check if the answer is confirmation.
    794      *
    795      * @param answer The answer user typed in.
    796      * @param defaultResult If true, default to yes; else, default to no.
    797      * @return If confirmation, return true; else, return false.
    798      */
    799     public static boolean isConfirmation(String answer, boolean defaultResult) {
    800         if ("".equals(answer)) {
    801             return defaultResult;
    802         }
    803 
    804         return ("y".equals(answer.toLowerCase()) || "yes".equals(answer.toLowerCase()));
    805     }
    806 
    807     /**
    808      * Process the add commands.
    809      * <ul>
    810      *     <li> Syntax 1:
    811      *            add --plan plan-name
    812      *     <li> Syntax 2:
    813      *            add --package package-name
    814      * </ul>
    815      *
    816      * @param cp Command container.
    817      */
    818     private void processAddCommand(CommandParser cp) {
    819         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    820             if (isValidAddPlanArguments(cp)) {
    821                 createPlan(cp, CTSCommand.OPTION_PLAN);
    822             } else {
    823                 showPlanCmdHelp();
    824             }
    825         } else if (cp.containsKey(CTSCommand.OPTION_DERIVED_PLAN)) {
    826             if (isValidDerivedPlanArguments(cp)) {
    827                 createPlan(cp, CTSCommand.OPTION_DERIVED_PLAN);
    828             } else {
    829                 showPlanCmdHelp();
    830             }
    831         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    832             try {
    833                 addPackage(cp);
    834             } catch (IOException e) {
    835                 Log.e("Can't add package", e);
    836             } catch (IndexOutOfBoundsException e) {
    837                 Log.e("Can't add package", e);
    838             } catch (NoSuchAlgorithmException e) {
    839                 Log.e("Can't add package", e);
    840             }
    841         } else {
    842             showHelp();
    843         }
    844     }
    845 
    846     /**
    847      * Check if it's valid arguments for adding plan.
    848      *
    849      * @param cp The command processor.
    850      * @return if valid, return true; else, return false.
    851      */
    852     private boolean isValidAddPlanArguments(CommandParser cp) {
    853         return (cp.getArgSize() == 3) && (cp.getActionValues().size() == 0)
    854                 && (cp.getOptionSize() == 1);
    855     }
    856 
    857     /**
    858      * Check if it's valid arguments for deriving plan.
    859      *
    860      * @param cp The command processor.
    861      * @return if valid, return true; else, return false.
    862      */
    863     private boolean isValidDerivedPlanArguments(CommandParser cp) {
    864         //argument size: it's at least 3, as "add --plan plan_name"
    865         //action values: no option contains more than one value
    866         //option size: it's at least 1, as "add --plan plan_name"
    867         return (cp.getArgSize() >= 3) && (cp.getActionValues().size() == 0)
    868                 && (cp.getOptionSize() >= 1);
    869     }
    870 
    871     /**
    872      * Process the history commands.
    873      * <ul>
    874      *     <li> Syntax:
    875      *            history [ -e ] [ number]
    876      * </ul>
    877      *
    878      * @param cp Command container.
    879      */
    880     private void processHistoryCommands(final CommandParser cp)
    881             throws Exception {
    882         try {
    883             if ((cp.getOptionSize() == 0) && (cp.getActionValues().size() == 0)) {
    884                 mCommandHistory.show(mCommandHistory.size());
    885             } else if (cp.containsKey(CTSCommand.OPTION_E)
    886                     && (cp.getActionValues().size() == 0)) {
    887                 int cmdNum = 0;
    888                 cmdNum = Integer.parseInt(cp.getValue(CTSCommand.OPTION_E));
    889                 if (cmdNum >= 0 && cmdNum < mCommandHistory.size()) {
    890                     String cmdLine = mCommandHistory.get(cmdNum);
    891                     CommandParser cpH = CommandParser.parse(cmdLine);
    892                     CUIOutputStream.printPrompt();
    893                     CUIOutputStream.println(cmdLine);// print(CTS_PROMPT_SIGN
    894                                                         // + cmdLine);
    895                     processCommand(cpH);
    896                     mCommandHistory.addCommand(cpH, cmdLine);
    897                 } else {
    898                     if (mCommandHistory.size() > 0) {
    899                         Log.e("Command index " + cmdNum
    900                                 + " is out of command history range [0,"
    901                                 + (mCommandHistory.size() - 1) + "].", null);
    902                     } else {
    903                         Log.e("No command exists in command history.", null);
    904                     }
    905                 }
    906             } else if ((cp.getOptionSize() == 0)
    907                     && (cp.getActionValues().size() == 1)) {
    908                 int cmdCount = Integer.parseInt(cp.getActionValues().iterator()
    909                         .next());
    910                 if (cmdCount < 0 || cmdCount > mCommandHistory.size()) {
    911                     cmdCount = mCommandHistory.size();
    912                 }
    913                 mCommandHistory.show(cmdCount);
    914             } else {
    915                 showHistoryCmdHelp();
    916             }
    917 
    918         } catch (NumberFormatException e) {
    919             showHistoryCmdHelp();
    920         }
    921     }
    922 
    923     /**
    924      * List a single plan by the plan name given.
    925      *
    926      * @param name The plan name.
    927      */
    928     private void listSinglePlan(String name) throws SAXException, IOException,
    929             ParserConfigurationException {
    930         String planName = null;
    931         for (String str : mHost.getPlanRepository().getAllPlanNames()) {
    932             if (str.startsWith(name)) {
    933                 planName = str;
    934                 break;
    935             }
    936         }
    937 
    938         if (planName == null) {
    939             Log.e("No plan named " + name + " in repository!", null);
    940             return;
    941         }
    942 
    943         String planPath = mHost.getPlanRepository().getPlanPath(planName);
    944         ArrayList<String> removedPkgList = new ArrayList<String>();
    945         Collection<String> pkgNames = TestPlan.getEntries(planPath, removedPkgList);
    946 
    947         if (removedPkgList.size() != 0) {
    948             CUIOutputStream.println("The following package(s) contained in plan "
    949                     + planName + " have been removed:");
    950             for (String pkgName : removedPkgList) {
    951                 CUIOutputStream.println("    " + pkgName);
    952             }
    953         }
    954 
    955         if (pkgNames.size() > 0) {
    956             CUIOutputStream.println("Packages of plan " + planName
    957                     + " (" + pkgNames.size() + " in total):");
    958             CUIOutputStream.println(LS_PLAN_SEPARATOR);
    959             for (String pkgName : pkgNames) {
    960                 CUIOutputStream.println(pkgName);
    961             }
    962         }
    963     }
    964 
    965     /**
    966      * Create test plan via the test session and result type given.
    967      *
    968      * @param name The test plan name.
    969      * @param ts The test session.
    970      * @param resultType The result type.
    971      */
    972     private void createPlanFromSession(final String name, TestSession ts, final String resultType)
    973             throws FileNotFoundException, ParserConfigurationException,
    974             TransformerFactoryConfigurationError, TransformerException {
    975 
    976         HashMap<String, ArrayList<String>> selectedResult =
    977             new HashMap<String, ArrayList<String>>();
    978         ArrayList<String> packageNames = new ArrayList<String>();
    979 
    980         for (TestPackage pkg : ts.getSessionLog().getTestPackages()) {
    981             String pkgName = pkg.getAppPackageName();
    982             ArrayList<String> excludedList = pkg.getExcludedList(resultType);
    983             if (excludedList != null) {
    984                 packageNames.add(pkgName);
    985                 selectedResult.put(pkgName, excludedList);
    986             }
    987         }
    988 
    989         if ((selectedResult != null) && (selectedResult.size() > 0)) {
    990             TestSessionBuilder.getInstance().serialize(name, packageNames, selectedResult);
    991         } else {
    992             if (resultType == null) {
    993                 Log.i("All tests of session " + ts.getId()
    994                         + " have passed execution. The plan is not created!");
    995             } else {
    996                 Log.i("No " + resultType +  " tests of session " + ts.getId()
    997                         + ". The plan is not created!");
    998             }
    999         }
   1000     }
   1001 
   1002     /**
   1003      * Add a derived plan from a given session.
   1004      *
   1005      * @param cp Command container.
   1006      * @param name The plan name.
   1007      * @param packageNames The package name list.
   1008      */
   1009     private void addDerivedPlan(final CommandParser cp, final String name,
   1010             ArrayList<String> packageNames) {
   1011 
   1012         try {
   1013             String sessionId = null;
   1014             String resultType = null;
   1015             int id = TestSession.getLastSessionId();
   1016 
   1017             if (cp.containsKey(CTSCommand.OPTION_SESSION)) {
   1018                 sessionId = cp.getValue(CTSCommand.OPTION_SESSION);
   1019                 id = Integer.parseInt(sessionId);
   1020             }
   1021             TestSession ts = mHost.getSession(id);
   1022             if (ts == null) {
   1023                 Log.e("The session ID of " + id + " doesn't exist.", null);
   1024                 return;
   1025             }
   1026 
   1027             if (cp.containsKey(CTSCommand.OPTION_RESULT)) {
   1028                 resultType = cp.getValue(CTSCommand.OPTION_RESULT);
   1029                 if (!CtsTestResult.isValidResultType(resultType)) {
   1030                     Log.e("The following result type is invalid: " + resultType, null);
   1031                     return;
   1032                 }
   1033             }
   1034             createPlanFromSession(name, ts, resultType);
   1035         } catch (Exception e) {
   1036             Log.e("Got exception while trying to add a plan!", e);
   1037             return;
   1038         }
   1039     }
   1040 
   1041     /**
   1042      * Add a plan by the plan name given.
   1043      *
   1044      * @param cp Command container.
   1045      * @param name The plan name.
   1046      * @param packageNames The package name list.
   1047      */
   1048     private void addPlan(final CommandParser cp, final String name,
   1049             ArrayList<String> packageNames) {
   1050 
   1051         try {
   1052             PlanBuilder planBuilder = new PlanBuilder(packageNames);
   1053 
   1054             if (mOsName.equals(OS_NAME_LINUX)) {
   1055                 // planBuilder.setInputStream(sConsoleReader);
   1056             } else {
   1057                 planBuilder.setInputStream(mCommandInput);
   1058             }
   1059 
   1060             HashMap<String, ArrayList<String>> selectedResult = planBuilder.doSelect();
   1061             if (selectedResult != null) {
   1062                 TestSessionBuilder.getInstance().serialize(name, packageNames, selectedResult);
   1063             } else {
   1064                 Log.i("Selected nothing for the plan of " + name + ". The plan is not created!");
   1065             }
   1066         } catch (Exception e) {
   1067             Log.e("Got exception while trying to add a plan!", e);
   1068             return;
   1069         }
   1070     }
   1071 
   1072     /**
   1073      * Create a plan.
   1074      *
   1075      * @param cp Command container.
   1076      * @param type the action type.
   1077      */
   1078     private void createPlan(final CommandParser cp, final String type) {
   1079         String name = null;
   1080         if (CTSCommand.OPTION_PLAN.equals(type)) {
   1081             name = cp.getValue(CTSCommand.OPTION_PLAN);
   1082         } else if (CTSCommand.OPTION_DERIVED_PLAN.equals(type)) {
   1083             name = cp.getValue(CTSCommand.OPTION_DERIVED_PLAN);
   1084         } else {
   1085             return;
   1086         }
   1087 
   1088         if (HostUtils.isFileExist(HostConfig.getInstance().getPlanRepository()
   1089                 .getPlanPath(name)) == true) {
   1090             Log.e("Plan " + name + " already exist, please use another name!", null);
   1091             return;
   1092         }
   1093 
   1094         try {
   1095             if ((name != null) && (!name.matches("\\w+"))) {
   1096                 CUIOutputStream.println("Only letter of the alphabet, number and '_'"
   1097                         + " are available for test plan name");
   1098                 return;
   1099             }
   1100 
   1101             ArrayList<String> packageNames =
   1102                 HostConfig.getInstance().getCaseRepository().getPackageNames();
   1103             Collection<TestPackage> testPackages = HostConfig.getInstance().getTestPackages();
   1104             if (testPackages.size() == 0) {
   1105                 CUIOutputStream.println("No package found in repository, please add package first!");
   1106                 return;
   1107             }
   1108             if (CTSCommand.OPTION_PLAN.equals(type)) {
   1109                 addPlan(cp, name, packageNames);
   1110             } else if (CTSCommand.OPTION_DERIVED_PLAN.equals(type)) {
   1111                 addDerivedPlan(cp, name, packageNames);
   1112             }
   1113         } catch (Exception e) {
   1114             Log.e("Got exception while trying to add a plan!", e);
   1115             return;
   1116         }
   1117     }
   1118 
   1119     /**
   1120      * List all of the plans in the plan repository.
   1121      */
   1122     private void listPlans() {
   1123         ArrayList<String> plans = mHost.getPlanRepository().getAllPlanNames();
   1124 
   1125         if (plans.size() == 0) {
   1126             CUIOutputStream.println("No plan created!");
   1127         } else {
   1128             CUIOutputStream.println("List of plans (" + plans.size() + " in total):");
   1129             for (String name : plans) {
   1130                 CUIOutputStream.println(name);
   1131             }
   1132         }
   1133     }
   1134 
   1135     /**
   1136      * List detailed case result of specified session. The result can be
   1137      * filtered, if resultType isn't null, by the specified resultType.
   1138      *
   1139      * @param idStr the session id.
   1140      * @param resultType the type of result, [pass, fail, notExecuted, timeout, null].
   1141      */
   1142     private void listSessionResult(final String idStr, final Integer resultType) {
   1143         if (!idStr.matches("\\d+")) {
   1144             showResultCmdHelp();
   1145             return;
   1146         }
   1147 
   1148         int sessionId = Integer.parseInt(idStr);
   1149 
   1150         TestSession ts = mHost.getSession(sessionId);
   1151         if (null == ts) {
   1152             Log.e("Can't find specified session", null);
   1153             return;
   1154         }
   1155 
   1156         TestSessionLog log = ts.getSessionLog();
   1157         CUIOutputStream.println("Result of session " + ts.getId());
   1158         CUIOutputStream.println("Result\t\tCase name");
   1159         CUIOutputStream
   1160                 .println("==============================================================");
   1161         for (Test test : log.getAllResults()) {
   1162             CtsTestResult result = test.getResult();
   1163             if ((resultType != null) && (result.getResultCode() != resultType.intValue())) {
   1164                 continue;
   1165             }
   1166             CUIOutputStream.println(result.getResultString() + "\t\t"
   1167                     + test.getFullName());
   1168         }
   1169     }
   1170 
   1171     /**
   1172      * List all of the test results.
   1173      */
   1174     private void listResults() {
   1175         Collection<TestSession> sessions = mHost.getSessions();
   1176         if (sessions.isEmpty()) {
   1177             CUIOutputStream.println("There isn't any test result!");
   1178         } else {
   1179             CUIOutputStream.println("List of all results: ");
   1180             CUIOutputStream.println(
   1181                     "Session\t\tTest result\t\t\t\tStart time\t\tEnd time\t\tTest plan name");
   1182             CUIOutputStream.println("\t\tPass\tFail\tTimeout\tNotExecuted");
   1183 
   1184             for (TestSession session : sessions) {
   1185                 TestSessionLog log = session.getSessionLog();
   1186                 int passNum = log.getTestList(
   1187                         CtsTestResult.CODE_PASS).size();
   1188                 int failNum = log.getTestList(
   1189                         CtsTestResult.CODE_FAIL).size();
   1190                 int notExecutedNum = log.getTestList(
   1191                         CtsTestResult.CODE_NOT_EXECUTED).size();
   1192                 int timeOutNum = log.getTestList(
   1193                         CtsTestResult.CODE_TIMEOUT).size();
   1194 
   1195                 String resStr = Long.toString(passNum) + "\t" + failNum;
   1196                 resStr += "\t" + timeOutNum;
   1197                 resStr += "\t" + notExecutedNum;
   1198 
   1199                 String startTimeStr =
   1200                     HostUtils.getFormattedTimeString(log.getStartTime().getTime(), " ", ".", ":");
   1201                 String endTimeStr =
   1202                     HostUtils.getFormattedTimeString(log.getEndTime().getTime(), " ", ".", ":");
   1203                 CUIOutputStream.println(Long.toString(session.getId()) + "\t\t"
   1204                         + resStr + "\t\t" + startTimeStr
   1205                         + "\t" + endTimeStr + "\t" + log.getTestPlanName());
   1206             }
   1207         }
   1208     }
   1209 
   1210     /**
   1211      * Add a package by the path and package name.
   1212      *
   1213      * @param cp Command container.
   1214      */
   1215     private void addPackage(final CommandParser cp) throws IOException,
   1216             IndexOutOfBoundsException, NoSuchAlgorithmException {
   1217         if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
   1218             showPackageCmdHelp();
   1219             return;
   1220         }
   1221         String pathName = cp.getValue(CTSCommand.OPTION_PACKAGE);
   1222         mHost.addPackage(pathName);
   1223     }
   1224 
   1225     /**
   1226      * List current package in the case repository.
   1227      *
   1228      * @param cp Command container
   1229      */
   1230     private void listPackages(final CommandParser cp) {
   1231         // walk through the case root path
   1232         // and list available packages
   1233         String expectPackage = cp.getValue(CTSCommand.OPTION_PACKAGE);
   1234         String caseRoot = mHost.getCaseRepository().getRoot();
   1235         if (caseRoot == null) {
   1236             Log.e("Case repository is null", null);
   1237             return;
   1238         }
   1239 
   1240         File root = new File(caseRoot);
   1241         if (!root.isDirectory()) {
   1242             Log.e("Case repository must be a directory!", null);
   1243             return;
   1244         }
   1245 
   1246         Collection<TestPackage> testPackages = HostConfig.getInstance().getTestPackages();
   1247 
   1248         if (testPackages.size() == 0) {
   1249             CUIOutputStream
   1250                     .println("No package available under case repository!");
   1251         } else {
   1252             if (expectPackage.equals("")) {
   1253                 CUIOutputStream.println("Available packages ("
   1254                         + testPackages.size() + " in total):");
   1255                 for (TestPackage pkg : testPackages) {
   1256                     CUIOutputStream.println(pkg.getAppPackageName());
   1257                 }
   1258             } else {
   1259                 List<ArrayList<String>> list = mHost.getCaseRepository()
   1260                         .listAvailablePackage(expectPackage);
   1261                 ArrayList<String> packageList = list.get(0);
   1262                 ArrayList<String> suiteList = list.get(1);
   1263                 ArrayList<String> caseList = list.get(2);
   1264                 ArrayList<String> testList = list.get(3);
   1265                 if ((packageList.size() == 0) && (suiteList.size() == 0)
   1266                         && (caseList.size() == 0) && (testList.size() == 0)) {
   1267                     CUIOutputStream
   1268                             .println("Not available test package, suite, cases or tests: "
   1269                                     + expectPackage);
   1270                 } else {
   1271                     if (packageList.size() != 0) {
   1272                         CUIOutputStream.println(
   1273                                 "Test packages (" + packageList.size() + " in total):");
   1274                         for (String packageName : packageList) {
   1275                             CUIOutputStream.println(packageName);
   1276                         }
   1277                     }
   1278                     if (suiteList.size() != 0) {
   1279                         CUIOutputStream.println(
   1280                                 "Test suites (" + suiteList.size() + " in total):");
   1281                         for (String suiteName : suiteList) {
   1282                             CUIOutputStream.println(suiteName);
   1283                         }
   1284                     }
   1285                     if (caseList.size() != 0) {
   1286                         CUIOutputStream.println("Test cases (" + caseList.size() + " in total):");
   1287                         for (String caseName : caseList) {
   1288                             CUIOutputStream.println(caseName);
   1289                         }
   1290                     }
   1291                     if (testList.size() != 0) {
   1292                         CUIOutputStream.println("Tests (" + testList.size() + " in total):");
   1293                         for (String testName : testList) {
   1294                             CUIOutputStream.println(testName);
   1295                         }
   1296                     }
   1297                 }
   1298             }
   1299         }
   1300     }
   1301 
   1302     /**
   1303      * List all of the devices connected.
   1304      */
   1305     private void listDevices() {
   1306         String[] deviceNames = mHost.listDevices();
   1307         if (deviceNames.length == 0) {
   1308             CUIOutputStream.println("No device connected.");
   1309             return;
   1310         }
   1311 
   1312         CUIOutputStream.println("Id\t\tDevice Name\t\tStatus");
   1313 
   1314         for (int i = 0; i < deviceNames.length; i++) {
   1315             CUIOutputStream.println(i + "\t\t" + deviceNames[i]);
   1316         }
   1317     }
   1318 }
   1319