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"
    264                 + ": run a specific test");
    265         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    266                 + cmdStr + " test_plan_name " + pkgStr + " java_package_name"
    267                 + ": run a specific java package");
    268         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    269                 + cmdStr + " test_plan_name " + testStr + " test_name "
    270                 + deviceStr + " device_ID"
    271                 + ": run a specific test using the specified device");
    272         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    273                 + cmdStr + " test_plan_name " + pkgStr + " java_package_name "
    274                 + deviceStr + " device_ID"
    275                 + ": run a specific java package using the specified device");
    276     }
    277 
    278     /**
    279      * Display the help message related to host commands.
    280      */
    281     private void showHostCmdHelp() {
    282         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Host:");
    283         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    284                 + CTSCommand.HELP + ": show this message");
    285         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    286                 + CTSCommand.EXIT + ": exit cts command line");
    287     }
    288 
    289     /**
    290      * Display the help message related to device commands.
    291      */
    292     private void showDeviceCmdHelp() {
    293         final String deviceStr = CTSCommand.OPTION_D + "/" + CTSCommand.OPTION_DEVICE;
    294 
    295         CUIOutputStream.println(CMD_TYPE_LEADING_SPACE + "Device:");
    296         CUIOutputStream.println(CMD_OPT_LEADING_SPACE
    297                 + CTSCommand.LIST + " " + deviceStr + ": list available devices");
    298     }
    299 
    300     /**
    301      * Process the command from user's input.
    302      *
    303      * @param cp Command container.
    304      */
    305     public void processCommand(final CommandParser cp) throws Exception {
    306         String action = cp.getAction();
    307 
    308         if (action.equals(CTSCommand.EXIT)) {
    309             if (cp.getArgSize() != 1) {
    310                 showHelp();
    311                 return;
    312             }
    313             Log.d("exit cts host");
    314             mKeepRunning = false;
    315             mHost.tearDown();
    316         } else if (action.equals(CTSCommand.HELP)) {
    317             showHelp();
    318         } else if (mCommandHistory.isHistoryCommand(action)) {
    319             processHistoryCommands(cp);
    320         } else if (action.equals(CTSCommand.ADD)) {
    321             processAddCommand(cp);
    322         } else if (action.equals(CTSCommand.START)) {
    323             processStartCommand(cp);
    324         } else if (action.equals(CTSCommand.REMOVE)) {
    325             processRmCommand(cp);
    326         } else if (action.equals(CTSCommand.LIST)) {
    327             processListCommand(cp);
    328         } else {
    329             showHelp();
    330         }
    331     }
    332 
    333     /**
    334      * Process start command.
    335      *
    336      * @param cp Command container.
    337      */
    338     private void processStartCommand(CommandParser cp) throws SAXException,
    339             ParserConfigurationException {
    340         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    341             processStartSessionCommand(cp);
    342         } else if (cp.containsKey(CTSCommand.OPTION_P)
    343                 || cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    344             processStartPackageCommand(cp);
    345         } else {
    346             showHelp();
    347         }
    348     }
    349 
    350     /**
    351      * Process start package command.
    352      *
    353      * <ul>
    354      *     <li> Syntax:
    355      *            start --package zipped-package-file
    356      * </ul>
    357      * @param cp Command container.
    358      */
    359     private void processStartPackageCommand(CommandParser cp) {
    360         try {
    361             String pathName = cp.getValue(CTSCommand.OPTION_PACKAGE);
    362             mHost.startZippedPackage(pathName);
    363         } catch (DeviceDisconnectedException e) {
    364           Log.e("Device " + e.getMessage() + " disconnected", e);
    365         } catch (Exception e) {
    366             Log.e("Met exception during running zipped package.", e);
    367         }
    368     }
    369 
    370     /**
    371      * Validate the command parameters used to activate CTS.
    372      *
    373      * @param cp Command container.
    374      * @return If command parameters are valid, return true; else, return false.
    375      */
    376     public boolean validateCommandParams(CommandParser cp) {
    377         if (cp == null) {
    378             return false;
    379         }
    380 
    381         if (cp.getAction() == null) {
    382             return true;
    383         } else if (isValidCommandOption(cp, CTSCommand.START,
    384                 CTSCommand.OPTION_PLAN)) {
    385             return true;
    386         } else if (isValidCommandOption(cp, CTSCommand.START,
    387                 CTSCommand.OPTION_PACKAGE)) {
    388             return true;
    389         } else if (isValidCommandOption(cp, CTSCommand.START,
    390                 CTSCommand.OPTION_P)) {
    391             return true;
    392         } else {
    393             return false;
    394         }
    395     }
    396 
    397     /**
    398      * Check if the command option is valid.
    399      *
    400      * @param cp CommandParser which contains the command and options.
    401      * @param command Command the user typed in.
    402      * @param option Option the user typed in.
    403      * @return If command option valid, return true; else, return false.
    404      */
    405     private static boolean isValidCommandOption(CommandParser cp,
    406             String command, String option) {
    407         return (cp.getAction().equals(command)) && (cp.containsKey(option))
    408                 && (cp.getValue(option) != null)
    409                 && (cp.getValue(option).length() != 0);
    410     }
    411 
    412     /**
    413      * Process start session command.
    414      * <ul>
    415      *     <li> Syntax 1:
    416      *            start --plan plan-name
    417      *              [ --device device-id ]
    418      *              [ --test test-name ]
    419      *              [ --profile profile-name ]
    420      *     <li> Syntax 2:
    421      *            start --plan plan-name
    422      *              [ --device device-id ]
    423      *              [ --package java-package-name ]
    424      *              [ --profile profile-name ]
    425      * </ul>
    426      * @param cp container which contained start command options and values
    427      *           Process the list commands.
    428      */
    429     private void processStartSessionCommand(CommandParser cp)
    430             throws SAXException, ParserConfigurationException {
    431 
    432         if (mHost.getDeviceList().length == 0) {
    433             Log.e("No device connected", null);
    434             return;
    435         }
    436 
    437         String testPlanPath = null;
    438         String deviceId = null;
    439         String testName = null;
    440         String javaPkgName = null;
    441         String testPlanName = mHost.getPlanName(cp.getValue(CTSCommand.OPTION_PLAN));
    442         try {
    443             if (cp.getActionValues().size() != 0 || cp.getOptionSize() < 1
    444                     || cp.getOptionSize() > 3) {
    445                 showStartSessionHelp();
    446                 return;
    447             }
    448             testPlanName = mHost.getPlanName(cp
    449                     .getValue(CTSCommand.OPTION_PLAN));
    450             testPlanPath = HostConfig.getInstance().getPlanRepository()
    451                     .getPlanPath(testPlanName);
    452             if (testPlanPath == null) {
    453                 CUIOutputStream.println("Plan " + testPlanName
    454                         + " is not in repository, please create it!");
    455                 return;
    456             }
    457 
    458             ActionType actionType = ActionType.START_NEW_SESSION;
    459             if (cp.containsKey(CTSCommand.OPTION_TEST)) {
    460                 testName = cp.getValue(CTSCommand.OPTION_TEST);
    461                 if (-1 == testName.indexOf(Test.METHOD_SEPARATOR)) {
    462                     Log.e("Test full name must be in the form of:"
    463                             + " java_package_name.class_name#method_name.", null);
    464                     return;
    465                 }
    466                 actionType = ActionType.RUN_SINGLE_TEST;
    467             } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    468                 javaPkgName = cp.getValue(CTSCommand.OPTION_PACKAGE);
    469                 actionType = ActionType.RUN_SINGLE_JAVA_PACKAGE;
    470             }
    471 
    472             TestSession ts = null;
    473             ArrayList<TestSession> sessionList = mHost.getSessionList(testPlanName);
    474             if ((sessionList != null) && (sessionList.size() > 0)) {
    475                 if ((testName == null) || (testName.length() == 0)) {
    476                     String mode = chooseMode(sessionList);
    477                     if (CREATE_SESSION.equals(mode)) {
    478                         ts = TestHost.createSession(testPlanName);
    479                     }
    480                 }
    481                 if (ts == null) {
    482                     ts = chooseTestSession(sessionList);
    483                     deviceId = ts.getDeviceId();
    484                     if ((actionType != ActionType.RUN_SINGLE_TEST)
    485                             && (actionType != ActionType.RUN_SINGLE_JAVA_PACKAGE)) {
    486                         actionType = ActionType.RESUME_SESSION;
    487                     }
    488                 }
    489             }
    490 
    491             if (cp.containsKey(CTSCommand.OPTION_DEVICE)) {
    492                 deviceId = cp.getValue(CTSCommand.OPTION_DEVICE);
    493                 String[] deviceIdList = deviceId.trim().split(",");
    494                 if (deviceIdList.length > 1) {
    495                     Log.e("Just allow choosing one device ID.", null);
    496                     return;
    497                 }
    498             }
    499 
    500             if (deviceId == null) {
    501                 TestDevice td = mHost.getFirstAvailableDevice();
    502                 if (td == null) {
    503                     // no devices attached
    504                     CUIOutputStream.println("No idle devices found.");
    505                     return;
    506                 }
    507                 deviceId = td.getSerialNumber();
    508             }
    509 
    510             if (!checkDeviceExists(mHost.getDeviceList(), deviceId)) {
    511                 CUIOutputStream.println("Can't find specified device id.  Is it attached?");
    512                 return;
    513             }
    514 
    515             if (ts == null) {
    516                 ts = TestHost.createSession(testPlanName);
    517             }
    518 
    519             mHost.startSession(ts, deviceId, testName, javaPkgName, actionType);
    520         } catch (IOException e) {
    521             Log.e("Can't create test session", e);
    522         } catch (DeviceNotAvailableException e) {
    523             CUIOutputStream.println("Test plan(" + testPlanName + ") "
    524                     + e.getMessage());
    525             showStartSessionHelp();
    526         } catch (TestNotFoundException e) {
    527             CUIOutputStream.println(e.getMessage());
    528         } catch (TestPlanNotFoundException e) {
    529             CUIOutputStream.println("Can't find test plan " + testPlanName);
    530         } catch (IllegalTestNameException e) {
    531             CUIOutputStream.println("Illegal case name: " + testName);
    532         } catch (DeviceDisconnectedException e) {
    533             Log.e("Device " + e.getMessage() + " disconnected ", null);
    534         } catch (NoSuchAlgorithmException e) {
    535             Log.e("Fail to initialise SHA-1 algorithm", e);
    536         } catch (InvalidApkPathException e) {
    537             Log.e(e.getMessage(), null);
    538         } catch (InvalidNameSpaceException e) {
    539             Log.e(e.getMessage(), null);
    540         }
    541     }
    542 
    543     /**
    544      * Choose test session among the available test session list.
    545      *
    546      * @param sessionList The available test session list.
    547      * @return The test session chosen.
    548      */
    549     private TestSession chooseTestSession(ArrayList<TestSession> sessionList) throws IOException {
    550         if ((sessionList == null) || (sessionList.size() == 0)) {
    551             return null;
    552         }
    553 
    554         if (sessionList.size() == 1) {
    555             return sessionList.get(0);
    556         }
    557 
    558         int index = 0;
    559         String notification = "Please choose a session from the existed session(s):\n";
    560         for (TestSession session : sessionList) {
    561             notification += "  " + session.getId() + "  [" + index + "] \n";
    562             index ++;
    563         }
    564 
    565         return sessionList.get(getUserInputId(notification, 0, index));
    566     }
    567 
    568     /**
    569      * Choose  between creating a new session and choosing a session among available ones.
    570      *
    571      * @param sessionList The available test session list.
    572      * @return If choose to create a new session, return CREATE_SESSION;
    573      *         else return CHOOSE_SESSION.
    574      */
    575     private String chooseMode(ArrayList<TestSession> sessionList) throws IOException {
    576         if (TestHost.sMode == MODE.RUN || (sessionList == null) || (sessionList.size() == 0)) {
    577             // do not prompt if the test run was started from command line mode, or when
    578             // there are no existing sessions
    579             return CREATE_SESSION;
    580         }
    581 
    582         String planName = sessionList.get(0).getSessionLog().getTestPlanName();
    583         String notification = "There are " + sessionList.size()
    584             + " existing session(s) for plan " + planName + ".\n"
    585             + "Create a new session or choose an existing one?\n"
    586             + "  Create a new session [0]\n"
    587             + "  Choose a session     [1]\n";
    588 
    589         int indexSelected = getUserInputId(notification, 0, 2);
    590         if (indexSelected == 0) {
    591             return CREATE_SESSION;
    592         } else {
    593             return CHOOSE_SESSION;
    594         }
    595     }
    596 
    597     /**
    598      * Validate the specified device ID against the available device array.
    599      *
    600      * @param availableDevices The available device array.
    601      * @param specifiedId The specified device ID list.
    602      * @return true if the id is valid
    603      */
    604     public boolean checkDeviceExists(TestDevice[] availableDevices, String specifiedId) {
    605         for (TestDevice dev : availableDevices) {
    606             if (specifiedId.equals(dev.getSerialNumber())) {
    607                 return true;
    608             }
    609         }
    610         return false;
    611     }
    612 
    613     /**
    614      * Get device ID from the device ID string against the available devices.
    615      *
    616      * @param availableDevices The available devices.
    617      * @param idStr The device ID string.
    618      * @return The device ID.
    619      */
    620     public int getDeviceId(TestDevice[] availableDevices, String idStr) {
    621         for (int i = 0; i < availableDevices.length; i++) {
    622             TestDevice dev = availableDevices[i];
    623             if (idStr.equals(dev.getSerialNumber())) {
    624                 return i;
    625             }
    626         }
    627         return -1;
    628     }
    629 
    630     /**
    631      * Get the ID input by the against the specified range.
    632      *
    633      * @param notification The notification message to notify the user.
    634      * @param startIndex The start index.
    635      * @param endIndex The end index.
    636      * @return The selected index of the ID the user chosen.
    637      */
    638     private int getUserInputId(String notification, int startIndex, int endIndex)
    639                 throws IOException {
    640         int indexSelected = 0;
    641         boolean success = false;
    642         while (!success) {
    643             String answer = readLine(notification);
    644             try {
    645                 indexSelected = Integer.parseInt(answer);
    646                 if ((indexSelected >= 0) && (indexSelected < endIndex)) {
    647                     success = true;
    648                 } else {
    649                     CUIOutputStream.println("" + indexSelected
    650                             + " is out of range [0," + (endIndex -1 ) + "].");
    651                 }
    652             } catch (NumberFormatException e) {
    653                 CUIOutputStream.println("Invalid nuber is typed in.");
    654             }
    655         }
    656         return indexSelected;
    657     }
    658 
    659     /**
    660      * Check if the specified device ID is valid.
    661      *
    662      * @param numOfAvailableDevices The number of available devices.
    663      * @param specifiedId The specified device ID.
    664      * @return If the specified ID contained in available ID list,
    665      *         return true; else, return false.
    666      */
    667     public boolean isValidDeviceId(int numOfAvailableDevices, int specifiedId) {
    668         if (specifiedId < 0 || specifiedId >= numOfAvailableDevices) {
    669             return false;
    670         }
    671         return true;
    672     }
    673 
    674     /**
    675      * Process list commands.
    676      * <ul>
    677      *     <li> Syntax 1:
    678      *            ls --device
    679      *     <li> Syntax 2:
    680      *            ls --plan [ plan-name ]
    681      *     <li> Syntax 3:
    682      *            ls --package [ package-name ]
    683      *     <li> Syntax 4:
    684      *            ls --result
    685      *              [ pass/fail/notExecuted/timeout ]
    686      *              [ --session session_id ]
    687      * </ul>
    688      *
    689      * @param cp Command container.
    690      */
    691     private void processListCommand(CommandParser cp) throws SAXException,
    692             IOException, ParserConfigurationException {
    693         if (cp.containsKey(CTSCommand.OPTION_DEVICE)) {
    694             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    695                 showDeviceCmdHelp();
    696                 return;
    697             }
    698             if (cp.getValue(CTSCommand.OPTION_DEVICE).equals("")) {
    699                 listDevices();
    700             } else {
    701                 showDeviceCmdHelp();
    702             }
    703         } else if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    704             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    705                 showPlanCmdHelp();
    706                 return;
    707             }
    708             String planValue = cp.getValue(CTSCommand.OPTION_PLAN);
    709             if (planValue.equals("")) {
    710                 listPlans();
    711             } else {
    712                 listSinglePlan(mHost.getPlanName(planValue));
    713             }
    714         } else if (cp.containsKey(CTSCommand.OPTION_RESULT)) {
    715             if (cp.getActionValues().size() != 0
    716                     || (cp.getOptionSize() < 1 || cp.getOptionSize() > 2)) {
    717                 showResultCmdHelp();
    718                 return;
    719             }
    720             String resultValue = cp.getValue(CTSCommand.OPTION_RESULT);
    721             String sessionId = cp.getValue(CTSCommand.OPTION_SESSION);
    722             Integer resultCode = null;
    723 
    724             if (sessionId != null) {
    725                 if (resultValue.length() != 0
    726                         && !mResultCodeMap.containsKey(resultValue)) {
    727                     showResultCmdHelp();
    728                 } else {
    729                     resultCode = mResultCodeMap.get(resultValue);
    730                     listSessionResult(sessionId, resultCode);
    731                 }
    732             } else if (resultValue.length() == 0) {
    733                 listResults();
    734             } else {
    735                 showHelp();
    736             }
    737         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    738             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    739                 showPackageCmdHelp();
    740                 return;
    741             }
    742             listPackages(cp);
    743         } else {
    744             showHelp();
    745         }
    746     }
    747 
    748     /**
    749      * Process the removing commands.
    750      * <ul>
    751      *     <li> Syntax 1:
    752      *            rm --plan [ plan-name ] [ all ]
    753      *     <li> Syntax 2:
    754      *            rm --package [ package-name ] [ all ]
    755      * </ul>
    756      *
    757      * @param cp Command container.
    758      */
    759     private void processRmCommand(CommandParser cp) throws IOException {
    760         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    761             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    762                 showPlanCmdHelp();
    763                 return;
    764             }
    765 
    766             String planName = mHost.getPlanName(cp.getValue(CTSCommand.OPTION_PLAN));
    767             if (HostConfig.ALL.equals(planName)) {
    768                 String prompt = "Remove all of the plans?([y/N])";
    769                 String answer = readLine(prompt).trim();
    770                 if (!isConfirmation(answer, false)) {
    771                     return;
    772                 }
    773             }
    774 
    775             mHost.removePlans(planName);
    776         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    777             if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
    778                 showPackageCmdHelp();
    779                 return;
    780             }
    781 
    782             String packageName = cp.getValue(CTSCommand.OPTION_PACKAGE);
    783             if (HostConfig.ALL.equals(packageName)) {
    784                 String prompt = "Remove all of the packages?([y/N])";
    785                 String answer = readLine(prompt).trim();
    786                 if (!isConfirmation(answer, false)) {
    787                     return;
    788                 }
    789             }
    790 
    791             mHost.removePackages(packageName);
    792         } else {
    793             showHelp();
    794         }
    795     }
    796 
    797     /**
    798      * Check if the answer is confirmation.
    799      *
    800      * @param answer The answer user typed in.
    801      * @param defaultResult If true, default to yes; else, default to no.
    802      * @return If confirmation, return true; else, return false.
    803      */
    804     public static boolean isConfirmation(String answer, boolean defaultResult) {
    805         if ("".equals(answer)) {
    806             return defaultResult;
    807         }
    808 
    809         return ("y".equals(answer.toLowerCase()) || "yes".equals(answer.toLowerCase()));
    810     }
    811 
    812     /**
    813      * Process the add commands.
    814      * <ul>
    815      *     <li> Syntax 1:
    816      *            add --plan plan-name
    817      *     <li> Syntax 2:
    818      *            add --package package-name
    819      * </ul>
    820      *
    821      * @param cp Command container.
    822      */
    823     private void processAddCommand(CommandParser cp) {
    824         if (cp.containsKey(CTSCommand.OPTION_PLAN)) {
    825             if (isValidAddPlanArguments(cp)) {
    826                 createPlan(cp, CTSCommand.OPTION_PLAN);
    827             } else {
    828                 showPlanCmdHelp();
    829             }
    830         } else if (cp.containsKey(CTSCommand.OPTION_DERIVED_PLAN)) {
    831             if (isValidDerivedPlanArguments(cp)) {
    832                 createPlan(cp, CTSCommand.OPTION_DERIVED_PLAN);
    833             } else {
    834                 showPlanCmdHelp();
    835             }
    836         } else if (cp.containsKey(CTSCommand.OPTION_PACKAGE)) {
    837             try {
    838                 addPackage(cp);
    839             } catch (IOException e) {
    840                 Log.e("Can't add package", e);
    841             } catch (IndexOutOfBoundsException e) {
    842                 Log.e("Can't add package", e);
    843             } catch (NoSuchAlgorithmException e) {
    844                 Log.e("Can't add package", e);
    845             }
    846         } else {
    847             showHelp();
    848         }
    849     }
    850 
    851     /**
    852      * Check if it's valid arguments for adding plan.
    853      *
    854      * @param cp The command processor.
    855      * @return if valid, return true; else, return false.
    856      */
    857     private boolean isValidAddPlanArguments(CommandParser cp) {
    858         return (cp.getArgSize() == 3) && (cp.getActionValues().size() == 0)
    859                 && (cp.getOptionSize() == 1);
    860     }
    861 
    862     /**
    863      * Check if it's valid arguments for deriving plan.
    864      *
    865      * @param cp The command processor.
    866      * @return if valid, return true; else, return false.
    867      */
    868     private boolean isValidDerivedPlanArguments(CommandParser cp) {
    869         //argument size: it's at least 3, as "add --plan plan_name"
    870         //action values: no option contains more than one value
    871         //option size: it's at least 1, as "add --plan plan_name"
    872         return (cp.getArgSize() >= 3) && (cp.getActionValues().size() == 0)
    873                 && (cp.getOptionSize() >= 1);
    874     }
    875 
    876     /**
    877      * Process the history commands.
    878      * <ul>
    879      *     <li> Syntax:
    880      *            history [ -e ] [ number]
    881      * </ul>
    882      *
    883      * @param cp Command container.
    884      */
    885     private void processHistoryCommands(final CommandParser cp)
    886             throws Exception {
    887         try {
    888             if ((cp.getOptionSize() == 0) && (cp.getActionValues().size() == 0)) {
    889                 mCommandHistory.show(mCommandHistory.size());
    890             } else if (cp.containsKey(CTSCommand.OPTION_E)
    891                     && (cp.getActionValues().size() == 0)) {
    892                 int cmdNum = 0;
    893                 cmdNum = Integer.parseInt(cp.getValue(CTSCommand.OPTION_E));
    894                 if (cmdNum >= 0 && cmdNum < mCommandHistory.size()) {
    895                     String cmdLine = mCommandHistory.get(cmdNum);
    896                     CommandParser cpH = CommandParser.parse(cmdLine);
    897                     CUIOutputStream.printPrompt();
    898                     CUIOutputStream.println(cmdLine);// print(CTS_PROMPT_SIGN
    899                                                         // + cmdLine);
    900                     processCommand(cpH);
    901                     mCommandHistory.addCommand(cpH, cmdLine);
    902                 } else {
    903                     if (mCommandHistory.size() > 0) {
    904                         Log.e("Command index " + cmdNum
    905                                 + " is out of command history range [0,"
    906                                 + (mCommandHistory.size() - 1) + "].", null);
    907                     } else {
    908                         Log.e("No command exists in command history.", null);
    909                     }
    910                 }
    911             } else if ((cp.getOptionSize() == 0)
    912                     && (cp.getActionValues().size() == 1)) {
    913                 int cmdCount = Integer.parseInt(cp.getActionValues().iterator()
    914                         .next());
    915                 if (cmdCount < 0 || cmdCount > mCommandHistory.size()) {
    916                     cmdCount = mCommandHistory.size();
    917                 }
    918                 mCommandHistory.show(cmdCount);
    919             } else {
    920                 showHistoryCmdHelp();
    921             }
    922 
    923         } catch (NumberFormatException e) {
    924             showHistoryCmdHelp();
    925         }
    926     }
    927 
    928     /**
    929      * List a single plan by the plan name given.
    930      *
    931      * @param name The plan name.
    932      */
    933     private void listSinglePlan(String name) throws SAXException, IOException,
    934             ParserConfigurationException {
    935         String planName = null;
    936         for (String str : mHost.getPlanRepository().getAllPlanNames()) {
    937             if (str.startsWith(name)) {
    938                 planName = str;
    939                 break;
    940             }
    941         }
    942 
    943         if (planName == null) {
    944             Log.e("No plan named " + name + " in repository!", null);
    945             return;
    946         }
    947 
    948         String planPath = mHost.getPlanRepository().getPlanPath(planName);
    949         ArrayList<String> removedPkgList = new ArrayList<String>();
    950         Collection<String> pkgNames = TestPlan.getEntries(planPath, removedPkgList);
    951 
    952         if (removedPkgList.size() != 0) {
    953             CUIOutputStream.println("The following package(s) contained in plan "
    954                     + planName + " have been removed:");
    955             for (String pkgName : removedPkgList) {
    956                 CUIOutputStream.println("    " + pkgName);
    957             }
    958         }
    959 
    960         if (pkgNames.size() > 0) {
    961             CUIOutputStream.println("Packages of plan " + planName
    962                     + " (" + pkgNames.size() + " in total):");
    963             CUIOutputStream.println(LS_PLAN_SEPARATOR);
    964             for (String pkgName : pkgNames) {
    965                 CUIOutputStream.println(pkgName);
    966             }
    967         }
    968     }
    969 
    970     /**
    971      * Create test plan via the test session and result type given.
    972      *
    973      * @param name The test plan name.
    974      * @param ts The test session.
    975      * @param resultType The result type.
    976      */
    977     private void createPlanFromSession(final String name, TestSession ts, final String resultType)
    978             throws FileNotFoundException, IOException, ParserConfigurationException,
    979             TransformerFactoryConfigurationError, TransformerException {
    980 
    981         HashMap<String, ArrayList<String>> selectedResult =
    982             new HashMap<String, ArrayList<String>>();
    983         ArrayList<String> packageNames = new ArrayList<String>();
    984 
    985         for (TestPackage pkg : ts.getSessionLog().getTestPackages()) {
    986             String pkgName = pkg.getAppPackageName();
    987             ArrayList<String> excludedList = pkg.getExcludedList(resultType);
    988             if (excludedList != null) {
    989                 packageNames.add(pkgName);
    990                 selectedResult.put(pkgName, excludedList);
    991             }
    992         }
    993 
    994         if ((selectedResult != null) && (selectedResult.size() > 0)) {
    995             TestSessionBuilder.getInstance().serialize(name, packageNames, selectedResult);
    996         } else {
    997             if (resultType == null) {
    998                 Log.i("All tests of session " + ts.getId()
    999                         + " have passed execution. The plan is not created!");
   1000             } else {
   1001                 Log.i("No " + resultType +  " tests of session " + ts.getId()
   1002                         + ". The plan is not created!");
   1003             }
   1004         }
   1005     }
   1006 
   1007     /**
   1008      * Add a derived plan from a given session.
   1009      *
   1010      * @param cp Command container.
   1011      * @param name The plan name.
   1012      * @param packageNames The package name list.
   1013      */
   1014     private void addDerivedPlan(final CommandParser cp, final String name,
   1015             ArrayList<String> packageNames) {
   1016 
   1017         try {
   1018             String sessionId = null;
   1019             String resultType = null;
   1020             int id = TestSession.getLastSessionId();
   1021 
   1022             if (cp.containsKey(CTSCommand.OPTION_SESSION)) {
   1023                 sessionId = cp.getValue(CTSCommand.OPTION_SESSION);
   1024                 id = Integer.parseInt(sessionId);
   1025             }
   1026             TestSession ts = mHost.getSession(id);
   1027             if (ts == null) {
   1028                 Log.e("The session ID of " + id + " doesn't exist.", null);
   1029                 return;
   1030             }
   1031 
   1032             if (cp.containsKey(CTSCommand.OPTION_RESULT)) {
   1033                 resultType = cp.getValue(CTSCommand.OPTION_RESULT);
   1034                 if (!CtsTestResult.isValidResultType(resultType)) {
   1035                     Log.e("The following result type is invalid: " + resultType, null);
   1036                     return;
   1037                 }
   1038             }
   1039             createPlanFromSession(name, ts, resultType);
   1040         } catch (Exception e) {
   1041             Log.e("Got exception while trying to add a plan!", e);
   1042             return;
   1043         }
   1044     }
   1045 
   1046     /**
   1047      * Add a plan by the plan name given.
   1048      *
   1049      * @param cp Command container.
   1050      * @param name The plan name.
   1051      * @param packageNames The package name list.
   1052      */
   1053     private void addPlan(final CommandParser cp, final String name,
   1054             ArrayList<String> packageNames) {
   1055 
   1056         try {
   1057             PlanBuilder planBuilder = new PlanBuilder(packageNames);
   1058 
   1059             if (mOsName.equals(OS_NAME_LINUX)) {
   1060                 // planBuilder.setInputStream(sConsoleReader);
   1061             } else {
   1062                 planBuilder.setInputStream(mCommandInput);
   1063             }
   1064 
   1065             HashMap<String, ArrayList<String>> selectedResult = planBuilder.doSelect();
   1066             if (selectedResult != null) {
   1067                 TestSessionBuilder.getInstance().serialize(name, packageNames, selectedResult);
   1068             } else {
   1069                 Log.i("Selected nothing for the plan of " + name + ". The plan is not created!");
   1070             }
   1071         } catch (Exception e) {
   1072             Log.e("Got exception while trying to add a plan!", e);
   1073             return;
   1074         }
   1075     }
   1076 
   1077     /**
   1078      * Create a plan.
   1079      *
   1080      * @param cp Command container.
   1081      * @param type the action type.
   1082      */
   1083     private void createPlan(final CommandParser cp, final String type) {
   1084         String name = null;
   1085         if (CTSCommand.OPTION_PLAN.equals(type)) {
   1086             name = cp.getValue(CTSCommand.OPTION_PLAN);
   1087         } else if (CTSCommand.OPTION_DERIVED_PLAN.equals(type)) {
   1088             name = cp.getValue(CTSCommand.OPTION_DERIVED_PLAN);
   1089         } else {
   1090             return;
   1091         }
   1092 
   1093         if (HostUtils.isFileExist(HostConfig.getInstance().getPlanRepository()
   1094                 .getPlanPath(name)) == true) {
   1095             Log.e("Plan " + name + " already exist, please use another name!", null);
   1096             return;
   1097         }
   1098 
   1099         try {
   1100             if ((name != null) && (!name.matches("\\w+"))) {
   1101                 CUIOutputStream.println("Only letter of the alphabet, number and '_'"
   1102                         + " are available for test plan name");
   1103                 return;
   1104             }
   1105 
   1106             ArrayList<String> packageNames =
   1107                 HostConfig.getInstance().getCaseRepository().getPackageNames();
   1108             Collection<TestPackage> testPackages = HostConfig.getInstance().getTestPackages();
   1109             if (testPackages.size() == 0) {
   1110                 CUIOutputStream.println("No package found in repository, please add package first!");
   1111                 return;
   1112             }
   1113             if (CTSCommand.OPTION_PLAN.equals(type)) {
   1114                 addPlan(cp, name, packageNames);
   1115             } else if (CTSCommand.OPTION_DERIVED_PLAN.equals(type)) {
   1116                 addDerivedPlan(cp, name, packageNames);
   1117             }
   1118         } catch (Exception e) {
   1119             Log.e("Got exception while trying to add a plan!", e);
   1120             return;
   1121         }
   1122     }
   1123 
   1124     /**
   1125      * List all of the plans in the plan repository.
   1126      */
   1127     private void listPlans() {
   1128         ArrayList<String> plans = mHost.getPlanRepository().getAllPlanNames();
   1129 
   1130         if (plans.size() == 0) {
   1131             CUIOutputStream.println("No plan created!");
   1132         } else {
   1133             CUIOutputStream.println("List of plans (" + plans.size() + " in total):");
   1134             for (String name : plans) {
   1135                 CUIOutputStream.println(name);
   1136             }
   1137         }
   1138     }
   1139 
   1140     /**
   1141      * List detailed case result of specified session. The result can be
   1142      * filtered, if resultType isn't null, by the specified resultType.
   1143      *
   1144      * @param idStr the session id.
   1145      * @param resultType the type of result, [pass, fail, notExecuted, timeout, null].
   1146      */
   1147     private void listSessionResult(final String idStr, final Integer resultType) {
   1148         if (!idStr.matches("\\d+")) {
   1149             showResultCmdHelp();
   1150             return;
   1151         }
   1152 
   1153         int sessionId = Integer.parseInt(idStr);
   1154 
   1155         TestSession ts = mHost.getSession(sessionId);
   1156         if (null == ts) {
   1157             Log.e("Can't find specified session", null);
   1158             return;
   1159         }
   1160 
   1161         TestSessionLog log = ts.getSessionLog();
   1162         CUIOutputStream.println("Result of session " + ts.getId());
   1163         CUIOutputStream.println("Result\t\tCase name");
   1164         CUIOutputStream
   1165                 .println("==============================================================");
   1166         for (Test test : log.getAllResults()) {
   1167             CtsTestResult result = test.getResult();
   1168             if ((resultType != null) && (result.getResultCode() != resultType.intValue())) {
   1169                 continue;
   1170             }
   1171             CUIOutputStream.println(result.getResultString() + "\t\t"
   1172                     + test.getFullName());
   1173         }
   1174     }
   1175 
   1176     /**
   1177      * List all of the test results.
   1178      */
   1179     private void listResults() {
   1180         Collection<TestSession> sessions = mHost.getSessions();
   1181         if (sessions.isEmpty()) {
   1182             CUIOutputStream.println("There aren't any test results!");
   1183         } else {
   1184             CUIOutputStream.println("List of all results: ");
   1185             CUIOutputStream.println("Session\t\tTest result\t\t\t\tStart time\t\tEnd time\t"
   1186                     + "\tTest plan name\t");
   1187             CUIOutputStream.println("\t\tPass\tFail\tTimeout\tNotExecuted");
   1188 
   1189             for (TestSession session : sessions) {
   1190                 TestSessionLog log = session.getSessionLog();
   1191                 int passNum = log.getTestList(
   1192                         CtsTestResult.CODE_PASS).size();
   1193                 int failNum = log.getTestList(
   1194                         CtsTestResult.CODE_FAIL).size();
   1195                 int notExecutedNum = log.getTestList(
   1196                         CtsTestResult.CODE_NOT_EXECUTED).size();
   1197                 int timeOutNum = log.getTestList(
   1198                         CtsTestResult.CODE_TIMEOUT).size();
   1199 
   1200                 String resStr = Long.toString(passNum) + "\t" + failNum;
   1201                 resStr += "\t" + timeOutNum;
   1202                 resStr += "\t" + notExecutedNum;
   1203 
   1204                 String startTimeStr =
   1205                     HostUtils.getFormattedTimeString(log.getStartTime().getTime(), " ", ".", ":");
   1206                 String endTimeStr =
   1207                     HostUtils.getFormattedTimeString(log.getEndTime().getTime(), " ", ".", ":");
   1208                 CUIOutputStream.println(Long.toString(session.getId()) + "\t\t"
   1209                         + resStr + "\t\t" + startTimeStr
   1210                         + "\t" + endTimeStr
   1211                         + "\t" + log.getTestPlanName());
   1212 
   1213             }
   1214         }
   1215     }
   1216 
   1217     /**
   1218      * Add a package by the path and package name.
   1219      *
   1220      * @param cp Command container.
   1221      */
   1222     private void addPackage(final CommandParser cp) throws IOException,
   1223             IndexOutOfBoundsException, NoSuchAlgorithmException {
   1224         if (cp.getActionValues().size() != 0 || cp.getOptionSize() != 1) {
   1225             showPackageCmdHelp();
   1226             return;
   1227         }
   1228         String pathName = cp.getValue(CTSCommand.OPTION_PACKAGE);
   1229         mHost.addPackage(pathName);
   1230     }
   1231 
   1232     /**
   1233      * List current package in the case repository.
   1234      *
   1235      * @param cp Command container
   1236      */
   1237     private void listPackages(final CommandParser cp) {
   1238         // walk through the case root path
   1239         // and list available packages
   1240         String expectPackage = cp.getValue(CTSCommand.OPTION_PACKAGE);
   1241         String caseRoot = mHost.getCaseRepository().getRoot();
   1242         if (caseRoot == null) {
   1243             Log.e("Case repository is null", null);
   1244             return;
   1245         }
   1246 
   1247         File root = new File(caseRoot);
   1248         if (!root.isDirectory()) {
   1249             Log.e("Case repository must be a directory!", null);
   1250             return;
   1251         }
   1252 
   1253         Collection<TestPackage> testPackages = HostConfig.getInstance().getTestPackages();
   1254 
   1255         if (testPackages.size() == 0) {
   1256             CUIOutputStream
   1257                     .println("No package available under case repository!");
   1258         } else {
   1259             if (expectPackage.equals("")) {
   1260                 CUIOutputStream.println("Available packages ("
   1261                         + testPackages.size() + " in total):");
   1262                 for (TestPackage pkg : testPackages) {
   1263                     CUIOutputStream.println(pkg.getAppPackageName());
   1264                 }
   1265             } else {
   1266                 List<ArrayList<String>> list = mHost.getCaseRepository()
   1267                         .listAvailablePackage(expectPackage);
   1268                 ArrayList<String> packageList = list.get(0);
   1269                 ArrayList<String> suiteList = list.get(1);
   1270                 ArrayList<String> caseList = list.get(2);
   1271                 ArrayList<String> testList = list.get(3);
   1272                 if ((packageList.size() == 0) && (suiteList.size() == 0)
   1273                         && (caseList.size() == 0) && (testList.size() == 0)) {
   1274                     CUIOutputStream
   1275                             .println("Not available test package, suite, cases or tests: "
   1276                                     + expectPackage);
   1277                 } else {
   1278                     if (packageList.size() != 0) {
   1279                         CUIOutputStream.println(
   1280                                 "Test packages (" + packageList.size() + " in total):");
   1281                         for (String packageName : packageList) {
   1282                             CUIOutputStream.println(packageName);
   1283                         }
   1284                     }
   1285                     if (suiteList.size() != 0) {
   1286                         CUIOutputStream.println(
   1287                                 "Test suites (" + suiteList.size() + " in total):");
   1288                         for (String suiteName : suiteList) {
   1289                             CUIOutputStream.println(suiteName);
   1290                         }
   1291                     }
   1292                     if (caseList.size() != 0) {
   1293                         CUIOutputStream.println("Test cases (" + caseList.size() + " in total):");
   1294                         for (String caseName : caseList) {
   1295                             CUIOutputStream.println(caseName);
   1296                         }
   1297                     }
   1298                     if (testList.size() != 0) {
   1299                         CUIOutputStream.println("Tests (" + testList.size() + " in total):");
   1300                         for (String testName : testList) {
   1301                             CUIOutputStream.println(testName);
   1302                         }
   1303                     }
   1304                 }
   1305             }
   1306         }
   1307     }
   1308 
   1309     /**
   1310      * List all of the devices connected.
   1311      */
   1312     private void listDevices() {
   1313         String[] deviceNames = mHost.listDevices();
   1314         if (deviceNames.length == 0) {
   1315             CUIOutputStream.println("No device connected.");
   1316             return;
   1317         }
   1318 
   1319         CUIOutputStream.println("Id\t\tDevice Name\t\tStatus");
   1320 
   1321         for (int i = 0; i < deviceNames.length; i++) {
   1322             CUIOutputStream.println(i + "\t\t" + deviceNames[i]);
   1323         }
   1324     }
   1325 }
   1326