diff options
10 files changed, 249 insertions, 15 deletions
diff --git a/src/components/application_manager/include/application_manager/application_manager_impl.h b/src/components/application_manager/include/application_manager/application_manager_impl.h index af7fe19f48..bda1e5f49e 100644 --- a/src/components/application_manager/include/application_manager/application_manager_impl.h +++ b/src/components/application_manager/include/application_manager/application_manager_impl.h @@ -415,6 +415,7 @@ class ApplicationManagerImpl * @brief Closes all registered applications */ void UnregisterAllApplications(); + bool ActivateApplication(ApplicationSharedPtr app) OVERRIDE; /** diff --git a/src/components/application_manager/include/application_manager/postponed_activation_controller.h b/src/components/application_manager/include/application_manager/postponed_activation_controller.h new file mode 100644 index 0000000000..e096800a25 --- /dev/null +++ b/src/components/application_manager/include/application_manager/postponed_activation_controller.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_POSTPONED_ACTIVATION_CONTROLLER_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_POSTPONED_ACTIVATION_CONTROLLER_H_ + +#include "application.h" + +namespace application_manager { + +/** + * @brief AppToActivateSet is a map of application ids expected to be + * activated after the registration is completed (default hmi level is assigned) + * and correlation_ids of the SDLActivateApp requests + */ +typedef std::map<uint32_t, uint32_t> AppToActivate; + +class PostponedActivationController { + public: + PostponedActivationController(); + + /** + * @brief AddAppToActivate adds app_id to app_to_activate_ map + * @param app_id id of the app that should be activated + * @param corr_id correlation_id of the SDLActivateApp request + */ + void AddAppToActivate(uint32_t app_id, uint32_t corr_id); + + /** + * @brief GetPendingActivationCorrId gets the pending + * activation correlation id + * @param app_id application id + * @return correlation id of the SDLActivateApp requests + */ + uint32_t GetPendingActivationCorrId(uint32_t app_id) const; + + /** + * @brief RemoveAppToActivate removes app_id from app_to_activate_ map + * @param app_id application id + */ + void RemoveAppToActivate(uint32_t app_id); + + private: + AppToActivate app_to_activate_; + mutable std::shared_ptr<sync_primitives::Lock> activate_app_list_lock_ptr_; +}; +} // namespace application_manager + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_POSTPONED_ACTIVATION_CONTROLLER_H_ diff --git a/src/components/application_manager/include/application_manager/state_controller_impl.h b/src/components/application_manager/include/application_manager/state_controller_impl.h index 210ddf9720..4dc4c1ad7d 100644 --- a/src/components/application_manager/include/application_manager/state_controller_impl.h +++ b/src/components/application_manager/include/application_manager/state_controller_impl.h @@ -133,6 +133,8 @@ class StateControllerImpl : public event_engine::EventObserver, void DropPostponedWindows(const uint32_t app_id) OVERRIDE; + PostponedActivationController& GetPostponedActivationController() OVERRIDE; + private: int64_t RequestHMIStateChange(ApplicationConstSharedPtr app, hmi_apis::Common_HMILevel::eType level, @@ -434,6 +436,7 @@ class StateControllerImpl : public event_engine::EventObserver, std::unordered_set<uint32_t> apps_with_pending_hmistatus_notification_; mutable sync_primitives::Lock apps_with_pending_hmistatus_notification_lock_; ApplicationManager& app_mngr_; + PostponedActivationController postponed_activation_controller_; }; } // namespace application_manager diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc index 372f83e4fd..66ac9c458b 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/hmi/sdl_activate_app_request.cc @@ -118,6 +118,15 @@ void SDLActivateAppRequest::Run() { ApplicationConstSharedPtr app = application_manager_.WaitingApplicationByID(app_id()); + + if (!app) { + app = application_manager_.application(app_id()); + if (!app) { + SDL_LOG_WARN("Can't find application within waiting apps: " << app_id()); + return; + } + } + if (application_manager_.state_controller().IsStateActive( HmiState::STATE_ID_DEACTIVATE_HMI)) { SDL_LOG_DEBUG( @@ -139,6 +148,18 @@ void SDLActivateAppRequest::Run() { application_manager_.connection_handler().ConnectToDevice(app->device()); } else { const uint32_t application_id = app_id(); + auto main_state = + app->CurrentHmiState(mobile_apis::PredefinedWindows::DEFAULT_WINDOW); + if (mobile_apis::HMILevel::INVALID_ENUM == main_state->hmi_level()) { + SDL_LOG_DEBUG( + "Application registration is not completed, HMI level hasn't set " + "yet, postpone activation"); + auto& postponed_activation_ctrl = application_manager_.state_controller() + .GetPostponedActivationController(); + postponed_activation_ctrl.AddAppToActivate(application_id, + correlation_id()); + return; + } policy_handler_.OnActivateApp(application_id, correlation_id()); } } @@ -186,6 +207,18 @@ void SDLActivateAppRequest::Run() { if (app_to_activate->IsRegistered()) { SDL_LOG_DEBUG("Application is registered. Activating."); + auto main_state = app_to_activate->CurrentHmiState( + mobile_apis::PredefinedWindows::DEFAULT_WINDOW); + if (mobile_apis::HMILevel::INVALID_ENUM == main_state->hmi_level()) { + SDL_LOG_DEBUG( + "Application registration is not completed, HMI level hasn't set " + "yet, postpone activation"); + auto& postponed_activation_ctrl = application_manager_.state_controller() + .GetPostponedActivationController(); + postponed_activation_ctrl.AddAppToActivate(application_id, + correlation_id()); + return; + } policy_handler_.OnActivateApp(application_id, correlation_id()); return; } else if (app_to_activate->is_cloud_app()) { @@ -269,6 +302,19 @@ void SDLActivateAppRequest::on_event(const event_engine::Event& event) { "Application not found by HMI app id: " << hmi_application_id); return; } + + auto main_state = + app->CurrentHmiState(mobile_apis::PredefinedWindows::DEFAULT_WINDOW); + if (mobile_apis::HMILevel::INVALID_ENUM == main_state->hmi_level()) { + SDL_LOG_DEBUG( + "Application registration is not completed, HMI level hasn't set " + "yet, postpone activation"); + auto& postponed_activation_ctrl = application_manager_.state_controller() + .GetPostponedActivationController(); + postponed_activation_ctrl.AddAppToActivate(app->app_id(), correlation_id()); + return; + } + policy_handler_.OnActivateApp(app->app_id(), correlation_id()); } diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc index 93344f1a0d..31285f5b17 100644 --- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc +++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/hmi/sdl_activate_app_request_test.cc @@ -40,6 +40,7 @@ #include "application_manager/mock_message_helper.h" #include "application_manager/mock_state_controller.h" #include "application_manager/policies/mock_policy_handler_interface.h" +#include "application_manager/postponed_activation_controller.h" #include "connection_handler/mock_connection_handler.h" #include "gtest/gtest.h" #include "hmi/sdl_activate_app_request.h" @@ -139,13 +140,20 @@ TEST_F(SDLActivateAppRequestTest, Run_ActivateApp_SUCCESS) { std::shared_ptr<SDLActivateAppRequest> command( CreateCommand<SDLActivateAppRequest>(msg)); + MockAppPtr mock_app(CreateMockApp()); EXPECT_CALL(app_mngr_, WaitingApplicationByID(kAppID)) - .WillOnce(Return(ApplicationSharedPtr())); - EXPECT_CALL(app_mngr_, state_controller()) - .WillOnce(ReturnRef(mock_state_controller_)); + .WillOnce(Return(mock_app)); + ON_CALL(app_mngr_, state_controller()) + .WillByDefault(ReturnRef(mock_state_controller_)); EXPECT_CALL(mock_state_controller_, IsStateActive(am::HmiState::StateID::STATE_ID_DEACTIVATE_HMI)) .WillOnce(Return(false)); + am::HmiStatePtr state = std::make_shared<am::HmiState>(mock_app, app_mngr_); + state->set_hmi_level(mobile_apis::HMILevel::HMI_NONE); + + EXPECT_CALL(*mock_app, + CurrentHmiState(mobile_apis::PredefinedWindows::DEFAULT_WINDOW)) + .WillOnce(Return(state)); EXPECT_CALL(mock_policy_handler_, OnActivateApp(kAppID, kCorrelationID)); @@ -303,7 +311,7 @@ TEST_F(SDLActivateAppRequestTest, FirstAppActive_SUCCESS) { command->Run(); } -TEST_F(SDLActivateAppRequestTest, FirstAppNotActive_SUCCESS) { +TEST_F(SDLActivateAppRequestTest, FirstAppNotActiveNONE_SUCCESS) { MessageSharedPtr msg = CreateMessage(); SetCorrelationAndAppID(msg); @@ -312,12 +320,18 @@ TEST_F(SDLActivateAppRequestTest, FirstAppNotActive_SUCCESS) { MockAppPtr mock_app(CreateMockApp()); ON_CALL(app_mngr_, application(kAppID)).WillByDefault(Return(mock_app)); - EXPECT_CALL(app_mngr_, state_controller()) - .WillOnce(ReturnRef(mock_state_controller_)); + ON_CALL(app_mngr_, state_controller()) + .WillByDefault(ReturnRef(mock_state_controller_)); EXPECT_CALL(mock_state_controller_, IsStateActive(am::HmiState::StateID::STATE_ID_DEACTIVATE_HMI)) .WillOnce(Return(false)); EXPECT_CALL(*mock_app, IsRegistered()).WillOnce(Return(true)); + am::HmiStatePtr state = std::make_shared<am::HmiState>(mock_app, app_mngr_); + state->set_hmi_level(mobile_apis::HMILevel::HMI_NONE); + + EXPECT_CALL(*mock_app, + CurrentHmiState(mobile_apis::PredefinedWindows::DEFAULT_WINDOW)) + .WillOnce(Return(state)); EXPECT_CALL(mock_policy_handler_, OnActivateApp(kAppID, kCorrelationID)); @@ -542,6 +556,10 @@ TEST_F(SDLActivateAppRequestTest, OnEvent_SUCCESS) { MockAppPtr mock_app(CreateMockApp()); EXPECT_CALL(app_mngr_, application_by_hmi_app(_)).WillOnce(Return(mock_app)); + + auto hmi_state = std::make_shared<am::HmiState>(mock_app, app_mngr_); + hmi_state->set_hmi_level(mobile_apis::HMILevel::HMI_NONE); + EXPECT_CALL(*mock_app, CurrentHmiState(_)).WillOnce(Return(hmi_state)); EXPECT_CALL(*mock_app, app_id()).WillOnce(Return(kAppID)); EXPECT_CALL(mock_policy_handler_, OnActivateApp(kAppID, kCorrelationID)); diff --git a/src/components/application_manager/src/postponed_activation_controller.cc b/src/components/application_manager/src/postponed_activation_controller.cc new file mode 100644 index 0000000000..59ee3d05e2 --- /dev/null +++ b/src/components/application_manager/src/postponed_activation_controller.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "application_manager/postponed_activation_controller.h" + +namespace application_manager { + +SDL_CREATE_LOG_VARIABLE("StateControllerImpl") + +PostponedActivationController::PostponedActivationController() + : activate_app_list_lock_ptr_(std::make_shared<sync_primitives::Lock>()) {} + +void PostponedActivationController::AddAppToActivate(uint32_t app_id, + uint32_t corr_id) { + SDL_LOG_AUTO_TRACE(); + sync_primitives::AutoLock lock(activate_app_list_lock_ptr_); + app_to_activate_.insert(std::pair<uint32_t, uint32_t>(app_id, corr_id)); +} + +uint32_t PostponedActivationController::GetPendingActivationCorrId( + uint32_t app_id) const { + SDL_LOG_AUTO_TRACE(); + sync_primitives::AutoLock lock(activate_app_list_lock_ptr_); + auto it = app_to_activate_.find(app_id); + if (app_to_activate_.end() == it) { + return 0; + } + return it->second; +} + +void PostponedActivationController::RemoveAppToActivate(uint32_t app_id) { + SDL_LOG_AUTO_TRACE(); + sync_primitives::AutoLock lock(activate_app_list_lock_ptr_); + app_to_activate_.erase(app_id); +} + +} // namespace application_manager diff --git a/src/components/application_manager/src/state_controller_impl.cc b/src/components/application_manager/src/state_controller_impl.cc index 7a231d4cfc..89dac83165 100644 --- a/src/components/application_manager/src/state_controller_impl.cc +++ b/src/components/application_manager/src/state_controller_impl.cc @@ -56,7 +56,9 @@ bool IsStateChanged(const HmiState& old_state, const HmiState& new_state) { } // unnamed namespace StateControllerImpl::StateControllerImpl(ApplicationManager& app_mngr) - : EventObserver(app_mngr.event_dispatcher()), app_mngr_(app_mngr) { + : EventObserver(app_mngr.event_dispatcher()) + , app_mngr_(app_mngr) + , postponed_activation_controller_() { subscribe_on_event(hmi_apis::FunctionID::BasicCommunication_OnAppActivated); subscribe_on_event(hmi_apis::FunctionID::BasicCommunication_OnAppDeactivated); subscribe_on_event(hmi_apis::FunctionID::TTS_Started); @@ -959,6 +961,19 @@ void StateControllerImpl::OnStateChanged(ApplicationSharedPtr app, app_mngr_.OnHMIStateChanged(app->app_id(), old_state, new_state); app->usage_report().RecordHmiStateChanged(new_state->hmi_level()); + + if (mobile_apis::HMILevel::INVALID_ENUM == old_state->hmi_level()) { + const auto app_default_hmi_level = app_mngr_.GetDefaultHmiLevel(app); + if (app_default_hmi_level == new_state->hmi_level()) { + const uint32_t app_id = app->app_id(); + const uint32_t corr_id = + postponed_activation_controller_.GetPendingActivationCorrId(app_id); + if (corr_id > 0) { + app_mngr_.GetPolicyHandler().OnActivateApp(app_id, corr_id); + postponed_activation_controller_.RemoveAppToActivate(app_id); + } + } + } } bool StateControllerImpl::IsTempStateActive(HmiState::StateID id) const { @@ -1011,11 +1026,6 @@ void StateControllerImpl::OnApplicationRegistered( const mobile_apis::HMILevel::eType default_level) { SDL_LOG_AUTO_TRACE(); - if (app->is_cloud_app()) { - // Return here, there should already be an onHMIStatus=FULL being processed - // for when the cloud app was initially activated by the hmi - return; - } // After app registration HMI level should be set for DEFAULT_WINDOW only OnAppWindowAdded(app, mobile_apis::PredefinedWindows::DEFAULT_WINDOW, @@ -1415,4 +1425,9 @@ mobile_apis::VideoStreamingState::eType StateControllerImpl::CalcVideoState( return state; } +PostponedActivationController& +StateControllerImpl::GetPostponedActivationController() { + return postponed_activation_controller_; +} + } // namespace application_manager diff --git a/src/components/application_manager/test/state_controller/state_controller_test.cc b/src/components/application_manager/test/state_controller/state_controller_test.cc index 374ad611ef..16e8bff8b8 100644 --- a/src/components/application_manager/test/state_controller/state_controller_test.cc +++ b/src/components/application_manager/test/state_controller/state_controller_test.cc @@ -1539,7 +1539,7 @@ TEST_F(StateControllerImplTest, MoveSimpleAppToValidStates) { namespace AudioStreamingState = mobile_apis::AudioStreamingState; namespace VideoStreamingState = mobile_apis::VideoStreamingState; namespace SystemContext = mobile_apis::SystemContext; - HmiStatePtr initial_state = createHmiState(HMILevel::INVALID_ENUM, + HmiStatePtr initial_state = createHmiState(HMILevel::HMI_NONE, AudioStreamingState::INVALID_ENUM, VideoStreamingState::INVALID_ENUM, SystemContext::INVALID_ENUM); @@ -1580,7 +1580,7 @@ TEST_F(StateControllerImplTest, MoveAudioNotResumeAppToValidStates) { NiceMock<application_manager_test::MockApplication>* audio_app_mock = media_navi_vc_app_ptr_; - HmiStatePtr initial_state = createHmiState(HMILevel::INVALID_ENUM, + HmiStatePtr initial_state = createHmiState(HMILevel::HMI_NONE, AudioStreamingState::INVALID_ENUM, VideoStreamingState::INVALID_ENUM, SystemContext::INVALID_ENUM); @@ -1619,7 +1619,7 @@ TEST_F(StateControllerImplTest, MoveAudioResumeAppToValidStates) { NiceMock<application_manager_test::MockApplication>* audio_app_mock = media_navi_vc_app_ptr_; - HmiStatePtr initial_state = createHmiState(HMILevel::INVALID_ENUM, + HmiStatePtr initial_state = createHmiState(HMILevel::HMI_NONE, AudioStreamingState::INVALID_ENUM, VideoStreamingState::INVALID_ENUM, SystemContext::INVALID_ENUM); diff --git a/src/components/include/application_manager/state_controller.h b/src/components/include/application_manager/state_controller.h index 422b34e0a0..e604675cea 100644 --- a/src/components/include/application_manager/state_controller.h +++ b/src/components/include/application_manager/state_controller.h @@ -35,9 +35,12 @@ #include "application_manager/application.h" #include "application_manager/application_manager.h" +#include "application_manager/postponed_activation_controller.h" #include "application_manager/request_controller_settings.h" #include "stdint.h" +class PostponedActivationController; + namespace application_manager { class StateController { public: @@ -246,6 +249,8 @@ class StateController { * @param app_id id of application to check */ virtual void DropPostponedWindows(const uint32_t app_id) = 0; + + virtual PostponedActivationController& GetPostponedActivationController() = 0; }; } // namespace application_manager diff --git a/src/components/include/test/application_manager/mock_state_controller.h b/src/components/include/test/application_manager/mock_state_controller.h index a06336467e..ca538bacb0 100644 --- a/src/components/include/test/application_manager/mock_state_controller.h +++ b/src/components/include/test/application_manager/mock_state_controller.h @@ -113,6 +113,8 @@ class MockStateController : public am::StateController { MOCK_METHOD2(DeactivateApp, void(am::ApplicationSharedPtr app, const am::WindowID window_id)); + MOCK_METHOD0(GetPostponedActivationController, + application_manager::PostponedActivationController&()); }; } // namespace application_manager_test |