#include #include #include #include #include #include #include #if SAILFISH #include static watchfish::WallTimeMonitor *monitor = 0; #endif #include "sapmanager.h" #include "sappeer.h" #include "hostmanagerconn.h" HostManagerConn::HostManagerConn(SAPConnection *conn, QObject *parent) : QObject(parent), _conn(conn), _socket(conn->getSocket(103)) { connect(_conn, SIGNAL(disconnected()), SLOT(deleteLater())); connect(_conn, SIGNAL(destroyed()), SLOT(deleteLater())); Q_ASSERT(_socket); connect(_socket, SIGNAL(connected()), SLOT(handleConnected())); connect(_socket, SIGNAL(messageReceived()), SLOT(handleMessageReceived())); } HostManagerConn::DeviceInfo HostManagerConn::parseDeviceInfo(const QString &xmlData) { QXmlStreamReader r(xmlData); DeviceInfo info; // TODO return info; } void HostManagerConn::sendMessage(const QJsonObject &msg) { QJsonDocument doc(msg); QByteArray data = doc.toJson(QJsonDocument::Compact); qDebug() << "Send JSON:" << data; _socket->send(QByteArray(2, '\0') + data); } void HostManagerConn::handleMessage(const QJsonObject &msg) { const QString msgId = msg["msgId"].toString(); qDebug() << "Got JSON msg" << msgId; if (msgId == "mgr_watch_info_res") { QJsonObject reply; QDateTime timestamp = QLocale("C").toDateTime(QString::fromLatin1(__DATE__ " " __TIME__).simplified(), "MMM d yyyy HH:mm:ss"); reply["timestamp"] = QString("%1_%2").arg(timestamp.toTime_t()) .arg(_conn->peer()->localName().right(2)); reply["type"] = QLatin1String("connect"); reply["msgId"] = QLatin1String("mgr_wearable_status_req"); sendMessage(reply); } else if (msgId == "mgr_wearable_status_res") { // Do nothing; watch will next ask for host status } else if (msgId == "mgr_host_status_req") { QJsonObject reply; reply["type"] = QLatin1String("connect"); reply["msgId"] = QLatin1String("mgr_host_status_res"); reply["preinstalled"] = QLatin1String("true"); reply["data"] = generateHostXml(); sendMessage(reply); } else if (msgId == "mgr_status_exchange_done") { performTimeSync(); QJsonObject reply; reply["btMac"] = _conn->peer()->localName(); reply["msgId"] = QLatin1String("mgr_setupwizard_eula_finished_req"); reply["isOld"] = 1; sendMessage(reply); } } void HostManagerConn::performTimeSync() { //{"date1224":"24","datetimeepoch":"1409343828044","safety_declared":"0","locale":"es_ES","safety_voice":"1", // "safetyVersion":0,"timezone":"Europe\/Madrid","safety":"false","tablet":"true","dateformat":"dd-MM-yyyy", // "isfrominitial":true,"msgId":"mgr_sync_init_setting_req","usingCamera":"false","safety_cam":"0", // "datetime":"2014 08 29 22 23 48","incomingCall":"false"} QJsonObject msg; msg["msgId"] = QLatin1String("mgr_sync_init_setting_req"); msg["safety_declared"] = QLatin1String("0"); msg["safety_voice"] = QLatin1String("0"); msg["safetyVersion"] = QLatin1String("0"); msg["safety"] = QLatin1String("false"); msg["tablet"] = QLatin1String("false"); msg["incomingCall"] = QLatin1String("false"); msg["usingCamera"] = QLatin1String("false"); msg["safety_cam"] = QLatin1String("0"); QLocale l = QLocale::system(); msg["locale"] = l.name(); // i.e. es_ES msg["date1224"] = l.timeFormat().contains('a', Qt::CaseInsensitive) ? QLatin1String("12") : QLatin1String("24"); msg["dateformat"] = QLocale::system().dateFormat(QLocale::ShortFormat); #if SAILFISH // QTimeZone does not seem to work on Sailfish; use timed. msg["timezone"] = monitor->timezone(); #else msg["timezone"] = QString::fromLatin1(QTimeZone::systemTimeZoneId()); #endif QDateTime dt = QDateTime::currentDateTime(); msg["datetimeepoch"] = QString::number(dt.currentMSecsSinceEpoch()); msg["datetime"] = dt.toString("yyyy MM dd hh mm ss"); sendMessage(msg); } QString HostManagerConn::generateHostXml() { QString xml; QXmlStreamWriter w(&xml); w.setCodec("UTF-8"); w.setAutoFormatting(true); w.writeStartDocument(); w.writeStartElement("DeviceStatus"); w.writeStartElement("device"); w.writeTextElement("deviceID", _conn->peer()->localName()); w.writeTextElement("deviceName", "none"); w.writeTextElement("devicePlatform", "android"); w.writeTextElement("devicePlatformVersion", "4.4.2"); w.writeTextElement("deviceType", "Host"); w.writeTextElement("modelNumber", "GT-I9500"); w.writeTextElement("swVersion", "android 4.4.2"); w.writeEmptyElement("connectivity"); #if 0 w.writeStartElement("apps"); SAPManager *manager = SAPManager::instance(); foreach (const SAPManager::RegisteredApplication &app, manager->allPackages()) { w.writeStartElement("app"); w.writeTextElement("name", app.name); w.writeTextElement("packagename", app.package); w.writeTextElement("version", QString::number(app.version)); w.writeTextElement("preloaded", app.preinstalled ? QLatin1String("true") : QLatin1String("false")); w.writeTextElement("isAppWidget", "false"); w.writeStartElement("features"); w.writeTextElement("Installed", "true"); w.writeEndElement(); w.writeEndElement(); } w.writeEndElement(); #else xml.append(QString::fromLatin1("" "Actualizar el software del Gearcom.sec.android.fotaprovider2falsefalse" "ConnectionManagercom.sec.android.service.connectionmanager1004falsefalse" "goproviderscom.samsung.accessory.goproviders61falsefalse" "SAFileTransferCorecom.samsung.accessory.safiletransfer1falsefalse" "SANotiProvidercom.samsung.accessory.sanotiprovider1falsefalse" "saproviderscom.samsung.accessory.saproviders64falsefalseTextTemplateProvidercom.samsung.accessory.texttemplateprovider1300falsefalse" "com.samsung.accessory.saproviders64com.samsung.w-calendar2truecom.samsung.accessory.goproviders61com.samsung.wfmdtrue" "com.sec.android.weatherprovidercom.samsung.weatherfalse" "com.samsung.accessory.goproviders61com.samsung.w-contacts2truecom.samsung.accessory.saproviders64com.samsung.w-media-controllertrue" "com.samsung.accessory.saproviders64com.samsung.alarmtruecom.samsung.accessory.saproviders64com.samsung.messagetrue" "com.samsung.accessory.saproviders64com.samsung.w-logs2truecom.samsung.accessory.saproviders64com.samsung.idle-clock-eventtrue" "com.sec.android.weatherprovidercom.samsung.w-idle-clock-weather2falsecom.samsung.accessory.saproviders64com.samsung.idle-clock-dualtrue" "com.samsung.accessory.saproviders64com.samsung.svoice-wtrue" "")); #endif w.writeStartElement("deviceFeature"); w.writeTextElement("telephony", "true"); w.writeTextElement("messaging", "true"); w.writeTextElement("tablet", "false"); w.writeTextElement("autolock", "true"); w.writeTextElement("smartrelay", "true"); w.writeTextElement("safetyassistance", "false"); w.writeTextElement("vendor", "Samsung"); w.writeEndElement(); w.writeEmptyElement("security"); w.writeEmptyElement("notification"); w.writeEmptyElement("settings"); w.writeEndElement(); w.writeEndElement(); w.writeEndDocument(); return xml; } void HostManagerConn::handleConnected() { qDebug() << "Manager socket now connected!"; #if SAILFISH if (!monitor) { monitor = new watchfish::WallTimeMonitor; } #endif QJsonObject obj; obj["btMac"] = _conn->peer()->localName(); obj["msgId"] = QLatin1String("mgr_watch_info_req"); obj["hmVer"] = QLatin1String("2.0.14041404"); sendMessage(obj); } void HostManagerConn::handleMessageReceived() { QByteArray data = _socket->receive(); if (data.size() < 4) { qWarning() << "Invalid HostManager message received"; return; } data.remove(0, 2); // Remove still-unknown header qDebug() << "Got JSON:" << QString::fromUtf8(data); QJsonParseError error; QJsonDocument json = QJsonDocument::fromJson(data, &error); if (json.isObject()) { handleMessage(json.object()); } else { qWarning() << "Cannot parse JSON msg:" << error.errorString(); } }