add xml report

- add getDeviceInfo command to get information from client
- rename ModelBuilderTest test case xml (all.xml gone)
- reduce buffer size for AudioTrack if data size is small
- add -s option
- generate XML report similar to CtsVerifier and zip the result.

Change-Id: Ic28e0234cfdb848ba1a2f91cc57f15bfdefafd87
diff --git a/suite/audio_quality/lib/include/GenericFactory.h b/suite/audio_quality/lib/include/GenericFactory.h
index 243a744..9f74b7f 100644
--- a/suite/audio_quality/lib/include/GenericFactory.h
+++ b/suite/audio_quality/lib/include/GenericFactory.h
@@ -18,8 +18,8 @@
 #define CTSAUDIO_GENERIC_FACTORY_H
 
 #include "task/TaskGeneric.h"
+#include "ClientInterface.h"
 
-class ClientInterface;
 
 /**
  * Factory methods for all abstract classes
diff --git a/suite/audio_quality/lib/include/Log.h b/suite/audio_quality/lib/include/Log.h
index 2b75bc2..e3e803c 100644
--- a/suite/audio_quality/lib/include/Log.h
+++ b/suite/audio_quality/lib/include/Log.h
@@ -59,6 +59,8 @@
 #define LOGD(x...) do { Log::Instance()->printf(Log::ELogD, x); } while(0)
 #define LOGV(x...) do { Log::Instance()->printf(Log::ELogV, x); } while(0)
 
+#define MSG(x...) do { Log::Instance()->printf(Log::ELogW, x); } while(0)
+
 #define ASSERT(cond) if(!(cond)) {  Log::Instance()->printf(Log::ELogE, \
         "assertion failed %s %d", __FILE__, __LINE__); \
     Log::Finalize(); \
diff --git a/suite/audio_quality/lib/include/Report.h b/suite/audio_quality/lib/include/Report.h
index 67a0572..248f4b9 100644
--- a/suite/audio_quality/lib/include/Report.h
+++ b/suite/audio_quality/lib/include/Report.h
@@ -37,13 +37,14 @@
 
     void addCasePassed(const android::String8& name);
     void addCaseFailed(const android::String8& name);
-    void printf(const char* fmt, ...);
+
 
 private:
     Report();
     ~Report();
     bool init(const char* dirName);
-    void writeSummary();
+    void writeReport();
+    void printf(const char* fmt, ...);
 
 private:
     static Report* mInstance;
diff --git a/suite/audio_quality/lib/include/Settings.h b/suite/audio_quality/lib/include/Settings.h
index 5cdcd7a..a8cfea5 100644
--- a/suite/audio_quality/lib/include/Settings.h
+++ b/suite/audio_quality/lib/include/Settings.h
@@ -25,13 +25,18 @@
     static Settings* Instance();
     static void Finalize();
     enum SettingType {
-        EADB
+        EADB            = 0, // adb device serial number
+        EREPORT_TIME    = 1,
+        EREPORT_FILE    = 2,
+        EDEVICE_INFO    = 3,
+        ETEST_XML       = 4, // name of test description xml
+        EMAX_SETTINGS   = 4  // not real setting
     };
     void addSetting(SettingType type, const android::String8 setting);
     const android::String8& getSetting(SettingType type);
 private:
     static Settings* mInstance;
-    android::String8 mAdbSetting;
+    android::String8 mSettings[EMAX_SETTINGS + 1];
 };
 
 
diff --git a/suite/audio_quality/lib/include/audio/AudioProtocol.h b/suite/audio_quality/lib/include/audio/AudioProtocol.h
index 83ba922..01e8507 100644
--- a/suite/audio_quality/lib/include/audio/AudioProtocol.h
+++ b/suite/audio_quality/lib/include/audio/AudioProtocol.h
@@ -37,6 +37,7 @@
     uint32_t mVolume;
     uint32_t mId;
     android::sp<Buffer> mBuffer;
+    void* mExtra; // extra data for whatever purpose
 };
 
 class AudioProtocol {
@@ -48,7 +49,8 @@
         ECmdStopPlayback        = 0x12340003,
         ECmdStartRecording      = 0x12340004,
         ECmdStopRecording       = 0x12340005,
-        ECmdLast                = 0x12340006, // not actual command
+        ECmdGetDeviceInfo       = 0x12340006,
+        ECmdLast                = 0x12340007, // not actual command
     };
 
     static const uint32_t REPLY_HEADER_SIZE = 12;
@@ -140,7 +142,13 @@
     virtual ~CmdStopRecording() {};
 };
 
+class CmdGetDeviceInfo: public AudioProtocol {
+public:
+    CmdGetDeviceInfo(ClientSocket& socket)
+        : AudioProtocol(socket, ECmdGetDeviceInfo) {};
+    virtual ~CmdGetDeviceInfo() {};
 
-
+    virtual bool handleReply(const uint32_t* data, AudioParam* param);
+};
 
 #endif // CTSAUDIO_AUDIOPROTOCOL_H
diff --git a/suite/audio_quality/lib/include/audio/RemoteAudio.h b/suite/audio_quality/lib/include/audio/RemoteAudio.h
index 4c587e6..26647c4 100644
--- a/suite/audio_quality/lib/include/audio/RemoteAudio.h
+++ b/suite/audio_quality/lib/include/audio/RemoteAudio.h
@@ -21,6 +21,7 @@
 #include <map>
 
 #include <utils/Looper.h>
+#include <utils/String8.h>
 #include <utils/StrongPointer.h>
 #include <utils/threads.h>
 
@@ -56,6 +57,8 @@
             android::sp<Buffer>& buffer);
     bool waitForRecordingCompletion();
     void stopRecording();
+
+    bool getDeviceInfo(android::String8& data);
     /** should be called before RemoteAudio is destroyed */
     void release();
 
@@ -139,6 +142,7 @@
     android::sp<android::MessageHandler> mDownloadHandler;
     android::sp<android::MessageHandler> mPlaybackHandler;
     android::sp<android::MessageHandler> mRecordingHandler;
+    android::sp<android::MessageHandler> mDeviceInfoHandler;
 
     AudioProtocol* mCmds[AudioProtocol::ECmdLast - AudioProtocol::ECmdStart];
     int mDownloadId;
diff --git a/suite/audio_quality/lib/src/FileUtil.cpp b/suite/audio_quality/lib/src/FileUtil.cpp
index e40b7e3..8c8ea7e 100644
--- a/suite/audio_quality/lib/src/FileUtil.cpp
+++ b/suite/audio_quality/lib/src/FileUtil.cpp
@@ -19,6 +19,7 @@
 #include <errno.h>
 
 #include "Log.h"
+#include "Settings.h"
 #include "StringUtil.h"
 #include "FileUtil.h"
 
@@ -54,9 +55,14 @@
         _LOGD_("mkdir of topdir failed, error %d", errno);
         return false;
     }
+    android::String8 reportTime;
+    if (reportTime.appendFormat("%04d_%02d_%02d_%02d_%02d_%02d", tm->tm_year + 1900,
+                tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec) != 0) {
+            return false;
+    }
+    Settings::Instance()->addSetting(Settings::EREPORT_TIME, reportTime);
     android::String8 path;
-    if (path.appendFormat("%s/%04d_%02d_%02d_%02d_%02d_%02d", reportTopDir,tm->tm_year + 1900,
-            tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec) != 0) {
+    if (path.appendFormat("%s/%s", reportTopDir, reportTime.string()) != 0) {
         return false;
     }
     result = mkdir(path.string(), S_IRWXU);
diff --git a/suite/audio_quality/lib/src/Report.cpp b/suite/audio_quality/lib/src/Report.cpp
index b487836..e6a248c 100644
--- a/suite/audio_quality/lib/src/Report.cpp
+++ b/suite/audio_quality/lib/src/Report.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "Log.h"
+#include "Settings.h"
 #include "StringUtil.h"
 #include "Report.h"
 
@@ -43,7 +44,7 @@
 
 Report::~Report()
 {
-    writeSummary();
+    writeReport();
 }
 
 bool Report::init(const char* dirName)
@@ -52,9 +53,10 @@
         return true;
     }
     android::String8 report;
-    if (report.appendFormat("%s/report.txt", dirName) != 0) {
+    if (report.appendFormat("%s/report.xml", dirName) != 0) {
         return false;
     }
+    Settings::Instance()->addSetting(Settings::EREPORT_FILE, report);
     return FileUtil::init(report.string());
 }
 
@@ -76,17 +78,24 @@
     mFailedCases.push_back(name);
 }
 
-void Report::writeSummary()
+void Report::writeReport()
 {
-    printf("= Test cases executed: %d, passed: %d, failed: %d =",
-            mPassedCases.size() + mFailedCases.size(), mPassedCases.size(), mFailedCases.size());
-    printf("= Failed cases =");
+    printf("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>");
+    printf("<audio-test-results-report report-version=\"1\" creation-time=\"%s\">",
+            Settings::Instance()->getSetting(Settings::EREPORT_TIME).string());
+    printf("  <verifier-info version-name=\"1\" version-code=\"1\" />");
+    printf("  <device-info>");
+    printf("    %s", Settings::Instance()->getSetting(Settings::EDEVICE_INFO).string());
+    printf("  </device-info>");
+    printf("  <audio-test-results xml=\"%s\">",
+            Settings::Instance()->getSetting(Settings::ETEST_XML).string());
     std::list<android::String8>::iterator it;
     for (it = mFailedCases.begin(); it != mFailedCases.end(); it++) {
-        printf("* %s", it->string());
+        printf("    <test title=\"%s\" result=\"fail\" />", it->string());
     }
-    printf("= Passed cases =");
     for (it = mPassedCases.begin(); it != mPassedCases.end(); it++) {
-        printf("* %s", it->string());
+        printf("    <test title=\"%s\" result=\"pass\" />", it->string());
     }
+    printf("  </audio-test-results>");
+    printf("</audio-test-results-report>");
 }
diff --git a/suite/audio_quality/lib/src/Settings.cpp b/suite/audio_quality/lib/src/Settings.cpp
index 4f78fe4..42dd30e 100644
--- a/suite/audio_quality/lib/src/Settings.cpp
+++ b/suite/audio_quality/lib/src/Settings.cpp
@@ -36,23 +36,11 @@
 
 void Settings::addSetting(SettingType type, const android::String8 setting)
 {
-    // TODO key, string can be better if there are large number of settings
-    switch(type) {
-    case EADB:
-        mAdbSetting = setting;
-    default:
-        ASSERT(false);
-    }
+    mSettings[type] = setting;
 }
 const android::String8& Settings::getSetting(SettingType type)
 {
-    switch(type) {
-    case EADB:
-        return mAdbSetting;
-    default:
-        ASSERT(false);
-    }
-    return mAdbSetting; // just for removing compiler warning, will not reach here
+    return mSettings[type];
 }
 
 
diff --git a/suite/audio_quality/lib/src/audio/AudioProtocol.cpp b/suite/audio_quality/lib/src/audio/AudioProtocol.cpp
index bf1ca22..c3457f5 100644
--- a/suite/audio_quality/lib/src/audio/AudioProtocol.cpp
+++ b/suite/audio_quality/lib/src/audio/AudioProtocol.cpp
@@ -19,6 +19,7 @@
 #include <sys/socket.h>
 
 #include <utils/StrongPointer.h>
+#include <utils/UniquePtr.h>
 
 #include "audio/Buffer.h"
 #include "Log.h"
@@ -171,6 +172,26 @@
     return true;
 }
 
+bool CmdGetDeviceInfo::handleReply(const uint32_t* data, AudioParam* param)
+{
+    if (!checkHeaderId(data, ECmdGetDeviceInfo)) {
+        return false;
+    }
+    if (data[1] != 0) { // no endian change for 0
+        LOGE("error in reply %d", ntohl(data[1]));
+        return false;
+    }
+    int len = ntohl(data[2]);
 
+    UniquePtr<char, DefaultDelete<char[]> > infoString(new char[len + 1]);
+    if (!readData(infoString.get(), len)) {
+        return false;
+    }
+    (infoString.get())[len] = 0;
+    LOGI("received data %s from device", infoString.get());
+    android::String8* string = reinterpret_cast<android::String8*>(param->mExtra);
+    string->setTo(infoString.get(), len);
+    return true;
+}
 
 
diff --git a/suite/audio_quality/lib/src/audio/RemoteAudio.cpp b/suite/audio_quality/lib/src/audio/RemoteAudio.cpp
index bb9474b..1156173 100644
--- a/suite/audio_quality/lib/src/audio/RemoteAudio.cpp
+++ b/suite/audio_quality/lib/src/audio/RemoteAudio.cpp
@@ -32,6 +32,7 @@
       mDownloadHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdDownload)),
       mPlaybackHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdStartPlayback)),
       mRecordingHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdStartRecording)),
+      mDeviceInfoHandler(new CommandHandler(*this, (int)AudioProtocol::ECmdGetDeviceInfo)),
       mDownloadId(0)
 {
     mCmds[AudioProtocol::ECmdDownload - AudioProtocol::ECmdStart] = new CmdDownload(socket);
@@ -43,6 +44,8 @@
             new CmdStartRecording(socket);
     mCmds[AudioProtocol::ECmdStopRecording - AudioProtocol::ECmdStart] =
             new CmdStopRecording(socket);
+    mCmds[AudioProtocol::ECmdGetDeviceInfo - AudioProtocol::ECmdStart] =
+                new CmdGetDeviceInfo(socket);
 }
 
 RemoteAudio::~RemoteAudio()
@@ -104,7 +107,6 @@
     if (!AudioProtocol::handleReplyHeader(mSocket, data, id)) {
         return false;
     }
-    AudioParam* param = NULL;
     CommandHandler* handler = NULL;
     if (id == AudioProtocol::ECmdDownload) {
         handler = reinterpret_cast<CommandHandler*>(mDownloadHandler.get());
@@ -112,6 +114,11 @@
         handler = reinterpret_cast<CommandHandler*>(mPlaybackHandler.get());
     } else if (id == AudioProtocol::ECmdStartRecording) {
         handler = reinterpret_cast<CommandHandler*>(mRecordingHandler.get());
+    } else if (id == AudioProtocol::ECmdGetDeviceInfo) {
+        handler = reinterpret_cast<CommandHandler*>(mDeviceInfoHandler.get());
+    }
+    AudioParam* param = NULL;
+    if (handler != NULL) {
         param = &(handler->getParam());
     }
     bool result = mCmds[id - AudioProtocol::ECmdStart]->handleReply(data, param);
@@ -148,6 +155,7 @@
 
 bool RemoteAudio::waitForCompletion(android::sp<android::MessageHandler>& command, int timeInMSec)
 {
+    LOGV("waitForCompletion %d", timeInMSec);
     return toCommandHandler(command)->timedWait(timeInMSec);
 }
 
@@ -190,12 +198,13 @@
     CommandHandler* handler = reinterpret_cast<CommandHandler*>(mDownloadHandler.get());
     id = mDownloadId;
     mDownloadId++;
+    handler->mStateLock.lock();
     handler->getParam().mId = id;
     handler->getParam().mBuffer = buffer;
-    sendCommand(mDownloadHandler);
-    handler->mStateLock.lock();
     handler->mNotifyOnReply = true;
     handler->mStateLock.unlock();
+    sendCommand(mDownloadHandler);
+
     // assume 1Mbps ==> 1000 bits per msec ==> 125 bytes per msec
     int maxWaitTime = CLIENT_WAIT_TIMEOUT_MSEC + buffer->getSize() / 125;
     // client blocked until reply comes from DUT
@@ -299,6 +308,23 @@
     doStop(mRecordingHandler, AudioProtocol::ECmdStopRecording);
 }
 
+bool RemoteAudio::getDeviceInfo(android::String8& data)
+{
+    CommandHandler* handler = reinterpret_cast<CommandHandler*>(mDeviceInfoHandler.get());
+    handler->mStateLock.lock();
+    handler->mNotifyOnReply = true;
+    handler->getParam().mExtra = &data;
+    handler->mStateLock.unlock();
+    sendCommand(mDeviceInfoHandler);
+
+    // client blocked until reply comes from DUT
+    if (!waitForCompletion(mDeviceInfoHandler, CLIENT_WAIT_TIMEOUT_MSEC)) {
+        LOGE("timeout");
+        return false;
+    }
+    return handler->mResult;
+}
+
 /** should be called before RemoteAudio is destroyed */
 void RemoteAudio::release()
 {
@@ -322,11 +348,13 @@
     case AudioProtocol::ECmdStopPlayback:
     case AudioProtocol::ECmdStartRecording:
     case AudioProtocol::ECmdStopRecording:
+    case AudioProtocol::ECmdGetDeviceInfo:
     {
         mResult = (mThread.mCmds[message.what - AudioProtocol::ECmdStart]) \
                 ->sendCommand(mParam);
-        // no post for download. Client blocked until reply comes with time-out
-        if (message.what != AudioProtocol::ECmdDownload) {
+        // no post for download and getdeviceinfo. Client blocked until reply comes with time-out
+        if ((message.what != AudioProtocol::ECmdDownload) &&
+            (message.what != AudioProtocol::ECmdGetDeviceInfo)    ) {
             mClientWait.post();
         }
 
diff --git a/suite/audio_quality/lib/src/task/TaskBatch.cpp b/suite/audio_quality/lib/src/task/TaskBatch.cpp
index f8c77fe..70499fc 100644
--- a/suite/audio_quality/lib/src/task/TaskBatch.cpp
+++ b/suite/audio_quality/lib/src/task/TaskBatch.cpp
@@ -58,10 +58,10 @@
     if (!findStringAttribute(STR_NAME, name) || !findStringAttribute(STR_VERSION, version)) {
         LOGW("TaskBatch::run no name or version information");
     }
-    Report::Instance()->printf("= Test batch %s version %s started. =", name.string(),
+    MSG("= Test batch %s version %s started. =", name.string(),
             version.string());
     bool result = TaskGeneric::forEachChild(runAlways, NULL);
-    Report::Instance()->printf("= Finished Test batch =");
+    MSG("= Finished Test batch =");
     return TaskGeneric::EResultOK;
 }
 
diff --git a/suite/audio_quality/lib/src/task/TaskCase.cpp b/suite/audio_quality/lib/src/task/TaskCase.cpp
index 9cbc6c8..c92e71b 100644
--- a/suite/audio_quality/lib/src/task/TaskCase.cpp
+++ b/suite/audio_quality/lib/src/task/TaskCase.cpp
@@ -300,8 +300,7 @@
     if (!findStringAttribute(STR_NAME, name) || !findStringAttribute(STR_VERSION, version)) {
         LOGW("TaskCase::run no name or version information");
     }
-    Report::Instance()->printf("== Test case %s version %s started ==", name.string(),
-            version.string());
+    MSG("== Test case %s version %s started ==", name.string(), version.string());
     std::list<TaskGeneric*>::iterator i = getChildren().begin();
     std::list<TaskGeneric*>::iterator end = getChildren().end();
     TaskGeneric* setup = *i;
@@ -316,12 +315,12 @@
     TaskGeneric::ExecutionResult result = setup->run();
     TaskGeneric::ExecutionResult resultAction(TaskGeneric::EResultOK);
     if (result != TaskGeneric::EResultOK) {
-        Report::Instance()->printf("== setup stage failed %d ==", result);
+        MSG("== setup stage failed %d ==", result);
         testPassed = false;
     } else {
         resultAction = action->run();
         if (resultAction != TaskGeneric::EResultPass) {
-            Report::Instance()->printf("== action stage failed %d ==", resultAction);
+            MSG("== action stage failed %d ==", resultAction);
             testPassed = false;
         }
         // save done even for failure if possible
@@ -329,19 +328,19 @@
             result = save->run();
         }
         if (result != TaskGeneric::EResultOK) {
-            Report::Instance()->printf("== save stage failed %d ==", result);
+            MSG("== save stage failed %d ==", result);
             testPassed = false;
         }
     }
     if (testPassed) {
         result = TaskGeneric::EResultPass;
-        Report::Instance()->printf("== Case %s Passed ==", name.string());
+        MSG("== Case %s Passed ==", name.string());
         Report::Instance()->addCasePassed(name);
     } else {
         if (resultAction != TaskGeneric::EResultOK) {
             result = resultAction;
         }
-        Report::Instance()->printf("== Case %s Failed ==", name.string());
+        MSG("== Case %s Failed ==", name.string());
         Report::Instance()->addCaseFailed(name);
     }
     // release remote audio for other cases to use
diff --git a/suite/audio_quality/lib/src/task/TaskSave.cpp b/suite/audio_quality/lib/src/task/TaskSave.cpp
index d62b846..8938c1e 100644
--- a/suite/audio_quality/lib/src/task/TaskSave.cpp
+++ b/suite/audio_quality/lib/src/task/TaskSave.cpp
@@ -110,7 +110,7 @@
         LOGE("alloc failed");
         return false;
     }
-    Report::Instance()->printf("=== Values stored ===");
+    MSG("=== Values stored ===");
     for (size_t i = 0; i < listp->size(); i++) {
         UniquePtr<std::list<TaskCase::ValuePair> > values(
                 getTestCase()->findAllValues((*listp)[i]));
@@ -123,11 +123,9 @@
         std::list<TaskCase::ValuePair>::iterator end = values->end();
         for (; it != end; it++) {
             if (it->second.getType() == TaskCase::Value::ETypeDouble) {
-                Report::Instance()->printf("   %s: %f", it->first.string(),
-                        it->second.getDouble());
+                MSG("   %s: %f", it->first.string(), it->second.getDouble());
             } else { //64bit int
-                Report::Instance()->printf("   %s: %lld", it->first.string(),
-                        it->second.getInt64());
+                MSG("   %s: %lld", it->first.string(), it->second.getInt64());
             }
         }
     }