ContentAppCommandDelegate.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. *
  3. * Copyright (c) 2021 Project CHIP Authors
  4. * All rights reserved.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. /**
  19. * @brief Contains Implementation of the ContentAppCommandDelegate
  20. */
  21. #include "ContentAppCommandDelegate.h"
  22. #include <app-common/zap-generated/cluster-objects.h>
  23. #include <app/CommandHandlerInterface.h>
  24. #include <app/util/config.h>
  25. #include <jni.h>
  26. #include <lib/core/DataModelTypes.h>
  27. #include <lib/support/CHIPJNIError.h>
  28. #include <lib/support/JniReferences.h>
  29. #include <lib/support/JniTypeWrappers.h>
  30. #include <lib/support/jsontlv/TlvJson.h>
  31. #include <zap-generated/endpoint_config.h>
  32. namespace chip {
  33. namespace AppPlatform {
  34. using CommandHandlerInterface = chip::app::CommandHandlerInterface;
  35. using LaunchResponseType = chip::app::Clusters::ContentLauncher::Commands::LauncherResponse::Type;
  36. using PlaybackResponseType = chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Type;
  37. using NavigateTargetResponseType = chip::app::Clusters::TargetNavigator::Commands::NavigateTargetResponse::Type;
  38. using GetSetupPINResponseType = chip::app::Clusters::AccountLogin::Commands::GetSetupPINResponse::Type;
  39. using Status = Protocols::InteractionModel::Status;
  40. const std::string FAILURE_KEY = "PlatformError";
  41. const std::string FAILURE_STATUS_KEY = "Status";
  42. void ContentAppCommandDelegate::InvokeCommand(CommandHandlerInterface::HandlerContext & handlerContext)
  43. {
  44. if (handlerContext.mRequestPath.mEndpointId >= FIXED_ENDPOINT_COUNT)
  45. {
  46. TLV::TLVReader readerForJson;
  47. readerForJson.Init(handlerContext.mPayload);
  48. CHIP_ERROR err = CHIP_NO_ERROR;
  49. Json::Value json;
  50. err = TlvToJson(readerForJson, json);
  51. if (err != CHIP_NO_ERROR)
  52. {
  53. handlerContext.SetCommandHandled();
  54. handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath,
  55. Protocols::InteractionModel::Status::InvalidCommand);
  56. return;
  57. }
  58. JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
  59. Json::Value value = json["value"];
  60. std::string payload = JsonToString(value);
  61. UtfString jsonString(env, payload.c_str());
  62. ChipLogProgress(Zcl, "ContentAppCommandDelegate::InvokeCommand send command being called with payload %s", payload.c_str());
  63. jstring resp = (jstring) env->CallObjectMethod(
  64. mContentAppEndpointManager, mSendCommandMethod, static_cast<jint>(handlerContext.mRequestPath.mEndpointId),
  65. static_cast<jlong>(handlerContext.mRequestPath.mClusterId), static_cast<jlong>(handlerContext.mRequestPath.mCommandId),
  66. jsonString.jniValue());
  67. if (env->ExceptionCheck())
  68. {
  69. ChipLogError(Zcl, "Java exception in ContentAppCommandDelegate::sendCommand");
  70. env->ExceptionDescribe();
  71. env->ExceptionClear();
  72. FormatResponseData(handlerContext, "{\"value\":{}}");
  73. }
  74. else
  75. {
  76. JniUtfString respStr(env, resp);
  77. ChipLogProgress(Zcl, "ContentAppCommandDelegate::InvokeCommand got response %s", respStr.c_str());
  78. FormatResponseData(handlerContext, respStr.c_str());
  79. }
  80. env->DeleteLocalRef(resp);
  81. }
  82. else
  83. {
  84. handlerContext.SetCommandNotHandled();
  85. }
  86. }
  87. Status ContentAppCommandDelegate::InvokeCommand(EndpointId epId, ClusterId clusterId, CommandId commandId, std::string payload,
  88. bool & commandHandled, Json::Value & value)
  89. {
  90. if (epId >= FIXED_ENDPOINT_COUNT)
  91. {
  92. JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
  93. UtfString jsonString(env, payload.c_str());
  94. ChipLogProgress(Zcl, "ContentAppCommandDelegate::InvokeCommand send command being called with payload %s", payload.c_str());
  95. jstring resp =
  96. (jstring) env->CallObjectMethod(mContentAppEndpointManager, mSendCommandMethod, static_cast<jint>(epId),
  97. static_cast<jlong>(clusterId), static_cast<jlong>(commandId), jsonString.jniValue());
  98. if (env->ExceptionCheck())
  99. {
  100. ChipLogError(Zcl, "Java exception in ContentAppCommandDelegate::sendCommand");
  101. env->ExceptionDescribe();
  102. env->ExceptionClear();
  103. }
  104. else
  105. {
  106. JniUtfString respStr(env, resp);
  107. ChipLogProgress(Zcl, "ContentAppCommandDelegate::InvokeCommand got response %s", respStr.c_str());
  108. Json::Reader reader;
  109. if (!reader.parse(respStr.c_str(), value))
  110. {
  111. env->DeleteLocalRef(resp);
  112. return Protocols::InteractionModel::Status::Failure;
  113. }
  114. }
  115. env->DeleteLocalRef(resp);
  116. // handle errors from platform-app
  117. if (!value[FAILURE_KEY].empty())
  118. {
  119. value = value[FAILURE_KEY];
  120. if (!value[FAILURE_STATUS_KEY].empty() && value[FAILURE_STATUS_KEY].isUInt())
  121. {
  122. return static_cast<Protocols::InteractionModel::Status>(value[FAILURE_STATUS_KEY].asUInt());
  123. }
  124. return Protocols::InteractionModel::Status::Failure;
  125. }
  126. return Protocols::InteractionModel::Status::UnsupportedEndpoint;
  127. }
  128. else
  129. {
  130. commandHandled = false;
  131. return Protocols::InteractionModel::Status::UnsupportedEndpoint;
  132. }
  133. }
  134. void ContentAppCommandDelegate::FormatResponseData(CommandHandlerInterface::HandlerContext & handlerContext, const char * response)
  135. {
  136. handlerContext.SetCommandHandled();
  137. Json::Reader reader;
  138. Json::Value value;
  139. if (!reader.parse(response, value))
  140. {
  141. return;
  142. }
  143. // handle errors from platform-app
  144. if (!value[FAILURE_KEY].empty())
  145. {
  146. value = value[FAILURE_KEY];
  147. if (!value[FAILURE_STATUS_KEY].empty() && value[FAILURE_STATUS_KEY].isUInt())
  148. {
  149. handlerContext.mCommandHandler.AddStatus(
  150. handlerContext.mRequestPath, static_cast<Protocols::InteractionModel::Status>(value[FAILURE_STATUS_KEY].asUInt()));
  151. return;
  152. }
  153. handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Protocols::InteractionModel::Status::Failure);
  154. return;
  155. }
  156. switch (handlerContext.mRequestPath.mClusterId)
  157. {
  158. case app::Clusters::ContentLauncher::Id: {
  159. Status status;
  160. LaunchResponseType launchResponse = FormatContentLauncherResponse(value, status);
  161. if (status != Protocols::InteractionModel::Status::Success)
  162. {
  163. handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, status);
  164. }
  165. else
  166. {
  167. handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, launchResponse);
  168. }
  169. break;
  170. }
  171. case app::Clusters::TargetNavigator::Id: {
  172. Status status;
  173. NavigateTargetResponseType navigateTargetResponse = FormatNavigateTargetResponse(value, status);
  174. if (status != Protocols::InteractionModel::Status::Success)
  175. {
  176. handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, status);
  177. }
  178. else
  179. {
  180. handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, navigateTargetResponse);
  181. }
  182. break;
  183. }
  184. case app::Clusters::MediaPlayback::Id: {
  185. Status status;
  186. PlaybackResponseType playbackResponse = FormatMediaPlaybackResponse(value, status);
  187. if (status != Protocols::InteractionModel::Status::Success)
  188. {
  189. handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, status);
  190. }
  191. else
  192. {
  193. handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, playbackResponse);
  194. }
  195. break;
  196. }
  197. case app::Clusters::AccountLogin::Id: {
  198. if (app::Clusters::AccountLogin::Commands::GetSetupPIN::Id != handlerContext.mRequestPath.mCommandId)
  199. {
  200. // No response for other commands in this cluster
  201. break;
  202. }
  203. Status status;
  204. GetSetupPINResponseType getSetupPINresponse = FormatGetSetupPINResponse(value, status);
  205. if (status != Protocols::InteractionModel::Status::Success)
  206. {
  207. handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, status);
  208. }
  209. else
  210. {
  211. handlerContext.mCommandHandler.AddResponseData(handlerContext.mRequestPath, getSetupPINresponse);
  212. }
  213. break;
  214. }
  215. default:
  216. handlerContext.SetCommandNotHandled();
  217. }
  218. }
  219. LaunchResponseType ContentAppCommandDelegate::FormatContentLauncherResponse(Json::Value value, Status & status)
  220. {
  221. status = Protocols::InteractionModel::Status::Success;
  222. LaunchResponseType launchResponse;
  223. std::string statusFieldId =
  224. std::to_string(to_underlying(app::Clusters::ContentLauncher::Commands::LauncherResponse::Fields::kStatus));
  225. if (value[statusFieldId].empty())
  226. {
  227. status = Protocols::InteractionModel::Status::Failure;
  228. return launchResponse;
  229. }
  230. else
  231. {
  232. launchResponse.status = static_cast<app::Clusters::ContentLauncher::ContentLaunchStatusEnum>(value[statusFieldId].asInt());
  233. std::string dataFieldId =
  234. std::to_string(to_underlying(app::Clusters::ContentLauncher::Commands::LauncherResponse::Fields::kData));
  235. if (!value[dataFieldId].empty())
  236. {
  237. launchResponse.data = chip::MakeOptional(CharSpan::fromCharString(value[dataFieldId].asCString()));
  238. }
  239. }
  240. return launchResponse;
  241. }
  242. NavigateTargetResponseType ContentAppCommandDelegate::FormatNavigateTargetResponse(Json::Value value, Status & status)
  243. {
  244. status = Protocols::InteractionModel::Status::Success;
  245. NavigateTargetResponseType navigateTargetResponse;
  246. std::string statusFieldId =
  247. std::to_string(to_underlying(app::Clusters::TargetNavigator::Commands::NavigateTargetResponse::Fields::kStatus));
  248. if (value[statusFieldId].empty())
  249. {
  250. status = Protocols::InteractionModel::Status::Failure;
  251. return navigateTargetResponse;
  252. }
  253. else
  254. {
  255. navigateTargetResponse.status =
  256. static_cast<app::Clusters::TargetNavigator::TargetNavigatorStatusEnum>(value[statusFieldId].asInt());
  257. std::string dataFieldId =
  258. std::to_string(to_underlying(app::Clusters::TargetNavigator::Commands::NavigateTargetResponse::Fields::kData));
  259. if (!value[dataFieldId].empty())
  260. {
  261. navigateTargetResponse.data = chip::MakeOptional(CharSpan::fromCharString(value[dataFieldId].asCString()));
  262. }
  263. }
  264. return navigateTargetResponse;
  265. }
  266. PlaybackResponseType ContentAppCommandDelegate::FormatMediaPlaybackResponse(Json::Value value, Status & status)
  267. {
  268. status = Protocols::InteractionModel::Status::Success;
  269. PlaybackResponseType playbackResponse;
  270. std::string statusFieldId =
  271. std::to_string(to_underlying(app::Clusters::MediaPlayback::Commands::PlaybackResponse::Fields::kStatus));
  272. if (value[statusFieldId].empty())
  273. {
  274. status = Protocols::InteractionModel::Status::Failure;
  275. return playbackResponse;
  276. }
  277. else
  278. {
  279. playbackResponse.status = static_cast<app::Clusters::MediaPlayback::MediaPlaybackStatusEnum>(value[statusFieldId].asInt());
  280. std::string dataFieldId =
  281. std::to_string(to_underlying(app::Clusters::MediaPlayback::Commands::PlaybackResponse::Fields::kData));
  282. if (!value[dataFieldId].empty())
  283. {
  284. playbackResponse.data = chip::MakeOptional(CharSpan::fromCharString(value[dataFieldId].asCString()));
  285. }
  286. }
  287. return playbackResponse;
  288. }
  289. GetSetupPINResponseType ContentAppCommandDelegate::FormatGetSetupPINResponse(Json::Value value, Status & status)
  290. {
  291. status = Protocols::InteractionModel::Status::Success;
  292. GetSetupPINResponseType getSetupPINresponse;
  293. std::string setupPINFieldId =
  294. std::to_string(to_underlying(app::Clusters::AccountLogin::Commands::GetSetupPINResponse::Fields::kSetupPIN));
  295. if (!value[setupPINFieldId].empty())
  296. {
  297. getSetupPINresponse.setupPIN = CharSpan::fromCharString(value[setupPINFieldId].asCString());
  298. }
  299. else
  300. {
  301. getSetupPINresponse.setupPIN = "";
  302. }
  303. return getSetupPINresponse;
  304. }
  305. } // namespace AppPlatform
  306. } // namespace chip