diff options
Diffstat (limited to 'src/components/application_manager/src/resumption/resume_ctrl_impl.cc')
-rw-r--r-- | src/components/application_manager/src/resumption/resume_ctrl_impl.cc | 473 |
1 files changed, 412 insertions, 61 deletions
diff --git a/src/components/application_manager/src/resumption/resume_ctrl_impl.cc b/src/components/application_manager/src/resumption/resume_ctrl_impl.cc index 72f2246e7c..3e77078ee5 100644 --- a/src/components/application_manager/src/resumption/resume_ctrl_impl.cc +++ b/src/components/application_manager/src/resumption/resume_ctrl_impl.cc @@ -35,6 +35,7 @@ #include <algorithm> #include "application_manager/application_manager.h" +#include "application_manager/rpc_service.h" #include "utils/file_system.h" #include "connection_handler/connection_handler_impl.h" @@ -47,17 +48,22 @@ #include "utils/helpers.h" #include "application_manager/resumption/resumption_data_db.h" #include "application_manager/resumption/resumption_data_json.h" -#include "utils/make_shared.h" + #include "utils/timer_task_impl.h" namespace resumption { using namespace application_manager; +static mobile_api::HMILevel::eType PickHigherHmiLevel( + mobile_api::HMILevel::eType val1, mobile_api::HMILevel::eType val2); +static mobile_api::HMILevel::eType PickLowerHmiLevel( + mobile_api::HMILevel::eType val1, mobile_api::HMILevel::eType val2); +static mobile_api::HMILevel::eType ConvertHmiLevelString(const std::string str); + CREATE_LOGGERPTR_GLOBAL(logger_, "Resumption") ResumeCtrlImpl::ResumeCtrlImpl(ApplicationManager& application_manager) : event_engine::EventObserver(application_manager.event_dispatcher()) - , queue_lock_(false) , restore_hmi_level_timer_( "RsmCtrlRstore", new timer::TimerTaskImpl<ResumeCtrlImpl>( @@ -68,13 +74,20 @@ ResumeCtrlImpl::ResumeCtrlImpl(ApplicationManager& application_manager) , is_resumption_active_(false) , is_data_saved_(false) , is_suspended_(false) - , launch_time_(time(NULL)) + , launch_time_(time(nullptr)) + , low_voltage_time_(0) + , wake_up_time_(0) , application_manager_(application_manager) {} #ifdef BUILD_TESTS void ResumeCtrlImpl::set_resumption_storage( - utils::SharedPtr<ResumptionData> mock_storage) { + std::shared_ptr<ResumptionData> mock_storage) { resumption_storage_ = mock_storage; } + +bool ResumeCtrlImpl::get_resumption_active() const { + sync_primitives::AutoLock auto_lock(queue_lock_); + return is_resumption_active_; +} #endif // BUILD_TESTS bool ResumeCtrlImpl::Init(resumption::LastState& last_state) { @@ -117,6 +130,8 @@ bool ResumeCtrlImpl::Init(resumption::LastState& last_state) { application_manager_.get_settings() .app_resumption_save_persistent_data_timeout(), timer::kPeriodic); + + resumption_storage_->IncrementGlobalIgnOnCounter(); return true; } @@ -133,9 +148,13 @@ void ResumeCtrlImpl::SaveAllApplications() { void ResumeCtrlImpl::SaveApplication(ApplicationSharedPtr application) { LOG4CXX_AUTO_TRACE(logger_); DCHECK_OR_RETURN_VOID(application); - LOG4CXX_INFO(logger_, - "application with appID " << application->app_id() - << " will be saved"); + if (application_manager_.IsLowVoltage()) { + LOG4CXX_DEBUG(logger_, "Low Voltage state is active"); + return; + } + LOG4CXX_DEBUG(logger_, + "application with appID " << application->app_id() + << " will be saved"); resumption_storage_->SaveApplication(application); } @@ -157,10 +176,38 @@ bool ResumeCtrlImpl::RestoreAppHMIState(ApplicationSharedPtr application) { if (result) { DCHECK_OR_RETURN(application, false); if (saved_app.keyExists(strings::hmi_level)) { - const HMILevel::eType saved_hmi_level = - static_cast<mobile_apis::HMILevel::eType>( - saved_app[strings::hmi_level].asInt()); - LOG4CXX_DEBUG(logger_, "Saved HMI Level is : " << saved_hmi_level); + HMILevel::eType saved_hmi_level; + if (HMILevel::eType::INVALID_ENUM != + application->deferred_resumption_hmi_level()) { + saved_hmi_level = application->deferred_resumption_hmi_level(); + LOG4CXX_INFO(logger_, + "Retry resuming into HMI level : " << saved_hmi_level); + application->set_deferred_resumption_hmi_level( + HMILevel::eType::INVALID_ENUM); + } else { + saved_hmi_level = static_cast<mobile_apis::HMILevel::eType>( + saved_app[strings::hmi_level].asInt()); + LOG4CXX_DEBUG(logger_, "Saved HMI Level is : " << saved_hmi_level); + } + + // Check one of the high-bandwidth transports (configured through + // smartDeviceLink.ini file) is available. If not, then the HMI level to + // resume into will be modified. + if (!application_manager_.CheckResumptionRequiredTransportAvailable( + application)) { + mobile_apis::HMILevel::eType low_bandwidth_level = + GetHmiLevelOnLowBandwidthTransport(application); + + application->set_deferred_resumption_hmi_level(saved_hmi_level); + + saved_hmi_level = + PickLowerHmiLevel(saved_hmi_level, low_bandwidth_level); + LOG4CXX_DEBUG( + logger_, + "High-bandwidth transport not available, app will resume into : " + << saved_hmi_level); + } + return SetAppHMIState(application, saved_hmi_level, true); } else { result = false; @@ -175,9 +222,23 @@ bool ResumeCtrlImpl::RestoreAppHMIState(ApplicationSharedPtr application) { bool ResumeCtrlImpl::SetupDefaultHMILevel(ApplicationSharedPtr application) { LOG4CXX_AUTO_TRACE(logger_); DCHECK_OR_RETURN(application, false); - mobile_apis::HMILevel::eType default_hmi = + mobile_apis::HMILevel::eType hmi_level = application_manager_.GetDefaultHmiLevel(application); - return SetAppHMIState(application, default_hmi, false); + + // Check one of the high-bandwidth transports (configured through + // smartDeviceLink.ini file) is available. If not, then the HMI level to + // resume into will be modified. + if (!application_manager_.CheckResumptionRequiredTransportAvailable( + application)) { + mobile_apis::HMILevel::eType low_bandwidth_level = + GetHmiLevelOnLowBandwidthTransport(application); + hmi_level = PickLowerHmiLevel(hmi_level, low_bandwidth_level); + LOG4CXX_DEBUG( + logger_, + "High-bandwidth transport not available, default HMI level is set to : " + << hmi_level); + } + return SetAppHMIState(application, hmi_level, false); } void ResumeCtrlImpl::ApplicationResumptiOnTimer() { @@ -257,6 +318,10 @@ uint32_t ResumeCtrlImpl::GetHMIApplicationID( bool ResumeCtrlImpl::RemoveApplicationFromSaved( ApplicationConstSharedPtr application) { + if (application_manager_.IsLowVoltage()) { + LOG4CXX_DEBUG(logger_, "Low Voltage state is active"); + return false; + } const std::string& device_mac = application->mac_address(); return resumption_storage_->RemoveApplicationFromSaved( application->policy_app_id(), device_mac); @@ -270,8 +335,11 @@ void ResumeCtrlImpl::OnSuspend() { void ResumeCtrlImpl::OnIgnitionOff() { LOG4CXX_AUTO_TRACE(logger_); - resumption_storage_->IncrementIgnOffCount(); - FinalPersistData(); + if (!application_manager_.IsLowVoltage()) { + resumption_storage_->IncrementIgnOffCount(); + resumption_storage_->ResetGlobalIgnOnCount(); + FinalPersistData(); + } } void ResumeCtrlImpl::OnAwake() { @@ -281,6 +349,25 @@ void ResumeCtrlImpl::OnAwake() { StartSavePersistentDataTimer(); } +void ResumeCtrlImpl::SaveLowVoltageTime() { + low_voltage_time_ = time(nullptr); + LOG4CXX_DEBUG(logger_, + "Low Voltage timestamp : " << low_voltage_time_ << " saved"); +} + +void ResumeCtrlImpl::SaveWakeUpTime() { + wake_up_time_ = std::time(nullptr); + LOG4CXX_DEBUG(logger_, "Wake Up timestamp : " << wake_up_time_ << " saved"); +} + +time_t ResumeCtrlImpl::LowVoltageTime() const { + return low_voltage_time_; +} + +time_t ResumeCtrlImpl::WakeUpTime() const { + return wake_up_time_; +} + bool ResumeCtrlImpl::is_suspended() const { return is_suspended_; } @@ -352,6 +439,28 @@ bool ResumeCtrlImpl::StartResumptionOnlyHMILevel( return result; } +void ResumeCtrlImpl::RetryResumption(const uint32_t app_id) { + LOG4CXX_AUTO_TRACE(logger_); + + ApplicationSharedPtr app = application_manager_.application(app_id); + if (!app) { + LOG4CXX_WARN(logger_, "Invalid app_id = " << app_id); + return; + } + + { + sync_primitives::AutoLock auto_lock(queue_lock_); + // check and update resumption deferred flag in queue_lock_ + if (mobile_api::HMILevel::eType::INVALID_ENUM == + app->deferred_resumption_hmi_level()) { + LOG4CXX_DEBUG(logger_, "No need to retry resumption for app: " << app_id); + return; + } + } + + AddToResumptionTimerQueue(app_id); +} + void ResumeCtrlImpl::StartAppHmiStateResumption( ApplicationSharedPtr application) { using namespace date_time; @@ -365,15 +474,33 @@ void ResumeCtrlImpl::StartAppHmiStateResumption( LOG4CXX_ERROR(logger_, "Application was not saved"); return; } - const uint32_t ign_off_count = saved_app[strings::ign_off_count].asUInt(); - bool restore_data_allowed = false; - restore_data_allowed = - CheckAppRestrictions(application, saved_app) && - ((0 == ign_off_count) || CheckIgnCycleRestrictions(saved_app)); - if (restore_data_allowed) { + + const bool is_hmi_level_applicable_to_resume = + CheckAppRestrictions(application, saved_app); + + if (!is_hmi_level_applicable_to_resume) { + LOG4CXX_DEBUG(logger_, "No applicable HMI level found for resuming"); + return; + } + + const bool is_resume_allowed_by_low_voltage = + CheckLowVoltageRestrictions(saved_app); + + const bool is_hmi_level_allowed_by_ign_cycle = + CheckIgnCycleRestrictions(saved_app); + + const bool restore_hmi_level_allowed = + is_resume_allowed_by_low_voltage && is_hmi_level_allowed_by_ign_cycle; + + if (restore_hmi_level_allowed) { LOG4CXX_INFO(logger_, "Resume application " << application->policy_app_id()); RestoreAppHMIState(application); + if (mobile_apis::HMILevel::eType::INVALID_ENUM != + application->deferred_resumption_hmi_level()) { + // the application has not been fully resumed + return; + } RemoveApplicationFromSaved(application); } else { LOG4CXX_INFO(logger_, @@ -544,8 +671,12 @@ void ResumeCtrlImpl::AddCommands(ApplicationSharedPtr application, saved_app[strings::application_commands]; for (size_t i = 0; i < app_commands.length(); ++i) { const smart_objects::SmartObject& command = app_commands[i]; + const uint32_t cmd_id = command[strings::cmd_id].asUInt(); + const bool is_resumption = true; - application->AddCommand(command[strings::cmd_id].asUInt(), command); + application->AddCommand(cmd_id, command); + application->help_prompt_manager().OnVrCommandAdded( + cmd_id, command, is_resumption); } ProcessHMIRequests(MessageHelper::CreateAddCommandRequestToHMI( application, application_manager_)); @@ -606,34 +737,25 @@ void ResumeCtrlImpl::AddSubscriptions( ApplicationSharedPtr application, const smart_objects::SmartObject& saved_app) { LOG4CXX_AUTO_TRACE(logger_); - if (saved_app.keyExists(strings::application_subscribtions)) { - const smart_objects::SmartObject& subscribtions = - saved_app[strings::application_subscribtions]; + if (saved_app.keyExists(strings::application_subscriptions)) { + const smart_objects::SmartObject& subscriptions = + saved_app[strings::application_subscriptions]; - if (subscribtions.keyExists(strings::application_buttons)) { - const smart_objects::SmartObject& subscribtions_buttons = - subscribtions[strings::application_buttons]; + if (subscriptions.keyExists(strings::application_buttons)) { + const smart_objects::SmartObject& subscriptions_buttons = + subscriptions[strings::application_buttons]; mobile_apis::ButtonName::eType btn; - for (size_t i = 0; i < subscribtions_buttons.length(); ++i) { + for (size_t i = 0; i < subscriptions_buttons.length(); ++i) { btn = static_cast<mobile_apis::ButtonName::eType>( - (subscribtions_buttons[i]).asInt()); + (subscriptions_buttons[i]).asInt()); application->SubscribeToButton(btn); } } MessageHelper::SendAllOnButtonSubscriptionNotificationsForApp( application, application_manager_); - if (subscribtions.keyExists(strings::application_vehicle_info)) { - const smart_objects::SmartObject& subscribtions_ivi = - subscribtions[strings::application_vehicle_info]; - mobile_apis::VehicleDataType::eType ivi; - for (size_t i = 0; i < subscribtions_ivi.length(); ++i) { - ivi = static_cast<mobile_apis::VehicleDataType::eType>( - (subscribtions_ivi[i]).asInt()); - application->SubscribeToIVI(ivi); - } - ProcessHMIRequests(MessageHelper::GetIVISubscriptionRequests( - application, application_manager_)); + for (auto& extension : application->Extensions()) { + extension->ProcessResumption(subscriptions); } } } @@ -641,30 +763,62 @@ void ResumeCtrlImpl::AddSubscriptions( bool ResumeCtrlImpl::CheckIgnCycleRestrictions( const smart_objects::SmartObject& saved_app) { LOG4CXX_AUTO_TRACE(logger_); - bool result = true; if (!CheckDelayAfterIgnOn()) { - LOG4CXX_INFO(logger_, "Application was connected long after ign on"); - result = false; + LOG4CXX_DEBUG(logger_, "Application was connected long after ign on"); + return false; } - if (!DisconnectedJustBeforeIgnOff(saved_app)) { - LOG4CXX_INFO(logger_, "Application was dissconnected long before ign off"); - result = false; + if (!CheckDelayBeforeIgnOff(saved_app)) { + LOG4CXX_DEBUG(logger_, "Application was disconnected long before ign off"); + return false; } - return result; + return true; } -bool ResumeCtrlImpl::DisconnectedJustBeforeIgnOff( +bool ResumeCtrlImpl::CheckLowVoltageRestrictions( const smart_objects::SmartObject& saved_app) { + LOG4CXX_AUTO_TRACE(logger_); + + if (!CheckDelayBeforeLowVoltage(saved_app)) { + LOG4CXX_DEBUG(logger_, + "Application was disconnected long before low voltage"); + return false; + } + + if (!CheckDelayAfterWakeUp()) { + LOG4CXX_DEBUG(logger_, "Application was connected long after wake up"); + return false; + } + + LOG4CXX_DEBUG(logger_, "HMI Level resuming in not restricted by Low Voltage"); + return true; +} + +bool ResumeCtrlImpl::CheckDelayBeforeIgnOff( + const smart_objects::SmartObject& saved_app) const { using namespace date_time; LOG4CXX_AUTO_TRACE(logger_); DCHECK_OR_RETURN(saved_app.keyExists(strings::time_stamp), false); const time_t time_stamp = static_cast<time_t>(saved_app[strings::time_stamp].asInt()); - time_t ign_off_time = + const time_t ign_off_time = static_cast<time_t>(resumption_storage_->GetIgnOffTime()); + + if (CheckIgnCyclesData() && 0 == ign_off_time) { + LOG4CXX_DEBUG( + logger_, "No IGNITION OFF records found: This is first Ignition cycle"); + return true; + } + + // This means that ignition off timestamp was not saved + // Possible reasons: Low Voltage event, core crash etc. + if (ign_off_time < time_stamp) { + LOG4CXX_DEBUG(logger_, "Last IGNITION OFF record missed"); + return true; + } + const uint32_t sec_spent_before_ign = labs(ign_off_time - time_stamp); LOG4CXX_DEBUG( logger_, @@ -677,6 +831,71 @@ bool ResumeCtrlImpl::DisconnectedJustBeforeIgnOff( application_manager_.get_settings().resumption_delay_before_ign(); } +bool ResumeCtrlImpl::CheckDelayBeforeLowVoltage( + const smart_objects::SmartObject& saved_app) const { + using namespace date_time; + LOG4CXX_AUTO_TRACE(logger_); + DCHECK_OR_RETURN(saved_app.keyExists(strings::time_stamp), false); + + if (0 == LowVoltageTime()) { + LOG4CXX_DEBUG(logger_, "No Low Voltage signal timestamp saved"); + return true; + } + + const time_t unregistration_time_stamp = + static_cast<time_t>(saved_app[strings::time_stamp].asInt()); + const time_t low_voltage_timestamp = static_cast<time_t>(LowVoltageTime()); + const int32_t sec_spent_before_low_voltage = + (low_voltage_timestamp - unregistration_time_stamp); + if (0 > sec_spent_before_low_voltage) { + LOG4CXX_DEBUG(logger_, + "Low Voltage time: " + << low_voltage_timestamp + << "; App disconnect time: " << unregistration_time_stamp + << "; Secs between app disconnect and low voltage event " + << sec_spent_before_low_voltage); + return true; + } + + const uint32_t secs_between_app_disconnect_and_low_voltage = + static_cast<uint32_t>(sec_spent_before_low_voltage); + const uint32_t wait_time = + application_manager_.get_settings().resumption_delay_before_ign(); + LOG4CXX_DEBUG(logger_, + "Low Voltage time: " + << low_voltage_timestamp + << "; App disconnect time: " << unregistration_time_stamp + << "; Secs between app disconnect and low voltage event " + << secs_between_app_disconnect_and_low_voltage + << "; Timeout for HMI level resuming: " << wait_time); + return secs_between_app_disconnect_and_low_voltage <= wait_time; +} + +bool ResumeCtrlImpl::CheckDelayAfterWakeUp() const { + using namespace date_time; + LOG4CXX_AUTO_TRACE(logger_); + + if (0 == WakeUpTime()) { + LOG4CXX_DEBUG(logger_, "No WakeUp signal timestamp saved"); + return true; + } + + const time_t current_time = time(nullptr); + const time_t wake_up_timestamp = static_cast<time_t>(WakeUpTime()); + + const uint32_t seconds_from_wake_up_signal = + labs(current_time - wake_up_timestamp); + const uint32_t wait_time = + application_manager_.get_settings().resumption_delay_after_ign(); + LOG4CXX_DEBUG( + logger_, + "Current time: " << current_time << "; WakeUp Signal time: " + << wake_up_timestamp << "; Seconds passed from wake up: " + << seconds_from_wake_up_signal + << "; Timeout for HMI level resuming: " << wait_time); + return seconds_from_wake_up_signal <= wait_time; +} + bool ResumeCtrlImpl::CheckAppRestrictions( ApplicationConstSharedPtr application, const smart_objects::SmartObject& saved_app) { @@ -685,16 +904,23 @@ bool ResumeCtrlImpl::CheckAppRestrictions( LOG4CXX_AUTO_TRACE(logger_); DCHECK_OR_RETURN(saved_app.keyExists(strings::hmi_level), false); - const HMILevel::eType hmi_level = - static_cast<HMILevel::eType>(saved_app[strings::hmi_level].asInt()); + HMILevel::eType hmi_level; + if (mobile_api::HMILevel::eType::INVALID_ENUM != + application->deferred_resumption_hmi_level()) { + hmi_level = application->deferred_resumption_hmi_level(); + } else { + hmi_level = + static_cast<HMILevel::eType>(saved_app[strings::hmi_level].asInt()); + } const bool result = Compare<HMILevel::eType, EQ, ONE>( hmi_level, HMILevel::HMI_FULL, HMILevel::HMI_LIMITED) ? true : false; LOG4CXX_DEBUG(logger_, - "is_media_app " << application->is_media_application() - << "; hmi_level " << hmi_level << " result " - << result); + "is_media_app: " << application->is_media_application() + << "; hmi_level: " << hmi_level << "; result: " + << (result ? "Applicable for resume" + : "Non-applicable for resume")); return result; } @@ -707,11 +933,36 @@ bool ResumeCtrlImpl::CheckIcons(ApplicationSharedPtr application, return mobile_apis::Result::INVALID_DATA != verify_images; } -bool ResumeCtrlImpl::CheckDelayAfterIgnOn() { +bool ResumeCtrlImpl::CheckIgnCyclesData() const { + LOG4CXX_AUTO_TRACE(logger_); + const uint32_t global_ign_on_count = + resumption_storage_->GetGlobalIgnOnCounter(); + const uint32_t the_first_ignition = 1; + const bool is_emergency_ign_off_occurred = + global_ign_on_count > the_first_ignition; + // global_ign_on_count is reseting to 0 at ignition off + // global_ign_on_count is incrementing at ignition on + // global_ign_on_count > 1 means that correct ignition off was not present. + if (is_emergency_ign_off_occurred) { + LOG4CXX_WARN(logger_, + "Emergency IGN OFF occurred. Possibly after Low Voltage"); + return false; + } + return true; +} + +bool ResumeCtrlImpl::CheckDelayAfterIgnOn() const { using namespace date_time; LOG4CXX_AUTO_TRACE(logger_); - const time_t curr_time = time(NULL); + const time_t ign_off_time = GetIgnOffTime(); + + if (CheckIgnCyclesData() && 0 == ign_off_time) { + LOG4CXX_DEBUG(logger_, "This is first Ignition cycle"); + return true; + } + const time_t curr_time = time(nullptr); const time_t sdl_launch_time = LaunchTime(); + const uint32_t seconds_from_sdl_start = labs(curr_time - sdl_launch_time); const uint32_t wait_time = application_manager_.get_settings().resumption_delay_after_ign(); @@ -727,7 +978,7 @@ time_t ResumeCtrlImpl::LaunchTime() const { return launch_time_; } -time_t ResumeCtrlImpl::GetIgnOffTime() { +time_t ResumeCtrlImpl::GetIgnOffTime() const { return resumption_storage_->GetIgnOffTime(); } @@ -743,7 +994,7 @@ bool ResumeCtrlImpl::ProcessHMIRequest(smart_objects::SmartObjectSPtr request, (*request)[strings::correlation_id].asInt(); subscribe_on_event(function_id, hmi_correlation_id); } - if (!application_manager_.ManageHMICommand(request)) { + if (!application_manager_.GetRPCService().ManageHMICommand(request)) { LOG4CXX_ERROR(logger_, "Unable to send request"); return false; } @@ -762,14 +1013,21 @@ void ResumeCtrlImpl::ProcessHMIRequests( void ResumeCtrlImpl::AddToResumptionTimerQueue(const uint32_t app_id) { LOG4CXX_AUTO_TRACE(logger_); + bool run_resumption = false; queue_lock_.Acquire(); waiting_for_timer_.push_back(app_id); + + if (!is_resumption_active_) { + is_resumption_active_ = true; + run_resumption = true; + } queue_lock_.Release(); LOG4CXX_DEBUG(logger_, "Application ID " << app_id << " have been added" " to resumption queue."); - if (!is_resumption_active_) { - is_resumption_active_ = true; + if (run_resumption) { + LOG4CXX_DEBUG(logger_, + "Application ID " << app_id << " will be restored by timer"); restore_hmi_level_timer_.Start( application_manager_.get_settings().app_resuming_timeout(), timer::kSingleShot); @@ -834,4 +1092,97 @@ bool ResumeCtrlImpl::IsAppDataResumptionExpired( return max_ign_off_count <= application[strings::ign_off_count].asInt(); } +mobile_apis::HMILevel::eType ResumeCtrlImpl::GetHmiLevelOnLowBandwidthTransport( + ApplicationConstSharedPtr application) const { + using namespace mobile_apis; + LOG4CXX_AUTO_TRACE(logger_); + + const ApplicationManagerSettings& settings = + application_manager_.get_settings(); + const std::string& level_for_navi_app = + settings.navigation_lowbandwidth_resumption_level(); + const std::string& level_for_projection_app = + settings.projection_lowbandwidth_resumption_level(); + const std::string& level_for_media_app = + settings.media_lowbandwidth_resumption_level(); + + HMILevel::eType result_level = HMILevel::HMI_NONE; + HMILevel::eType level; + + // NAVIGATION, PROJECTION and media apps have special exceptions. Their HMI + // level can be configured through .ini file. when the app has multiple + // AppHMIType, then the highest level will be applied. + if (application->is_navi()) { + level = ConvertHmiLevelString(level_for_navi_app); + LOG4CXX_DEBUG(logger_, + "NAVIGATION apps may have level " + << level + << " while high-bandwidth transport is not available."); + result_level = PickHigherHmiLevel(level, result_level); + } + if (application->mobile_projection_enabled()) { + level = ConvertHmiLevelString(level_for_projection_app); + LOG4CXX_DEBUG(logger_, + "PROJECTION apps may have level " + << level + << " while high-bandwidth transport is not available."); + result_level = PickHigherHmiLevel(level, result_level); + } + if (application->is_media_application()) { + level = ConvertHmiLevelString(level_for_media_app); + LOG4CXX_DEBUG(logger_, + "media apps may have level " + << level + << " while high-bandwidth transport is not available."); + result_level = PickHigherHmiLevel(level, result_level); + } + + return result_level; +} + +static mobile_api::HMILevel::eType PickHigherHmiLevel( + mobile_api::HMILevel::eType val1, mobile_api::HMILevel::eType val2) { + using namespace mobile_apis; + + if (val1 == HMILevel::INVALID_ENUM) { + return val2; + } else if (val2 == HMILevel::INVALID_ENUM) { + return val1; + } + + // smaller enum value has higher level + return val1 < val2 ? val1 : val2; +} + +static mobile_api::HMILevel::eType PickLowerHmiLevel( + mobile_api::HMILevel::eType val1, mobile_api::HMILevel::eType val2) { + using namespace mobile_apis; + + if (val1 == HMILevel::INVALID_ENUM) { + return val2; + } else if (val2 == HMILevel::INVALID_ENUM) { + return val1; + } + + // bigger enum value has lower level + return val1 > val2 ? val1 : val2; +} + +static mobile_api::HMILevel::eType ConvertHmiLevelString( + const std::string str) { + using namespace mobile_apis; + + if ("BACKGROUND" == str) { + return HMILevel::HMI_BACKGROUND; + } else if ("FULL" == str) { + return HMILevel::HMI_FULL; + } else if ("LIMITED" == str) { + return HMILevel::HMI_LIMITED; + } else if ("NONE" == str) { + return HMILevel::HMI_NONE; + } else { + return HMILevel::HMI_NONE; + } +} + } // namespce resumption |