/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "PowerManager.h" #include "FileItem.h" #include "PowerTypes.h" #include "ServiceBroker.h" #include "application/AppParams.h" #include "application/Application.h" #include "application/ApplicationComponents.h" #include "application/ApplicationPlayer.h" #include "application/ApplicationPowerHandling.h" #include "application/ApplicationStackHelper.h" #include "cores/AudioEngine/Interfaces/AE.h" #include "dialogs/GUIDialogBusyNoCancel.h" #include "dialogs/GUIDialogKaiToast.h" #include "guilib/GUIComponent.h" #include "guilib/GUIWindowManager.h" #include "guilib/LocalizeStrings.h" #include "interfaces/AnnouncementManager.h" #include "network/Network.h" #include "pvr/PVRManager.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "settings/lib/Setting.h" #include "settings/lib/SettingDefinitions.h" #include "settings/lib/SettingsManager.h" #include "utils/log.h" #include "weather/WeatherManager.h" #include #include #if defined(TARGET_WINDOWS_DESKTOP) extern HWND g_hWnd; #endif CPowerManager::CPowerManager() : m_settings(CServiceBroker::GetSettingsComponent()->GetSettings()) { m_settings->GetSettingsManager()->RegisterSettingOptionsFiller("shutdownstates", SettingOptionsShutdownStatesFiller); } CPowerManager::~CPowerManager() = default; void CPowerManager::Initialize() { m_instance.reset(IPowerSyscall::CreateInstance()); } void CPowerManager::SetDefaults() { auto setting = m_settings->GetSetting(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNSTATE); if (!setting) { CLog::Log(LOGERROR, "Failed to load setting for: {}", CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNSTATE); return; } int defaultShutdown = m_settings->GetInt(CSettings::SETTING_POWERMANAGEMENT_SHUTDOWNSTATE); switch (defaultShutdown) { case POWERSTATE_QUIT: case POWERSTATE_MINIMIZE: // assume we can shutdown if --standalone is passed if (CServiceBroker::GetAppParams()->IsStandAlone()) defaultShutdown = POWERSTATE_SHUTDOWN; break; case POWERSTATE_HIBERNATE: if (!CServiceBroker::GetPowerManager().CanHibernate()) { if (CServiceBroker::GetPowerManager().CanSuspend()) defaultShutdown = POWERSTATE_SUSPEND; else defaultShutdown = CServiceBroker::GetPowerManager().CanPowerdown() ? POWERSTATE_SHUTDOWN : POWERSTATE_QUIT; } break; case POWERSTATE_SUSPEND: if (!CServiceBroker::GetPowerManager().CanSuspend()) { if (CServiceBroker::GetPowerManager().CanHibernate()) defaultShutdown = POWERSTATE_HIBERNATE; else defaultShutdown = CServiceBroker::GetPowerManager().CanPowerdown() ? POWERSTATE_SHUTDOWN : POWERSTATE_QUIT; } break; case POWERSTATE_SHUTDOWN: if (!CServiceBroker::GetPowerManager().CanPowerdown()) { if (CServiceBroker::GetPowerManager().CanSuspend()) defaultShutdown = POWERSTATE_SUSPEND; else defaultShutdown = CServiceBroker::GetPowerManager().CanHibernate() ? POWERSTATE_HIBERNATE : POWERSTATE_QUIT; } break; } std::static_pointer_cast(setting)->SetDefault(defaultShutdown); } bool CPowerManager::Powerdown() { if (CanPowerdown() && m_instance->Powerdown()) { CGUIDialogBusyNoCancel* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_BUSY_NOCANCEL); if (dialog) dialog->Open(); return true; } return false; } bool CPowerManager::Suspend() { return (CanSuspend() && m_instance->Suspend()); } bool CPowerManager::Hibernate() { return (CanHibernate() && m_instance->Hibernate()); } bool CPowerManager::Reboot() { bool success = CanReboot() ? m_instance->Reboot() : false; if (success) { CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::System, "OnRestart"); CGUIDialogBusyNoCancel* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_BUSY_NOCANCEL); if (dialog) dialog->Open(); } return success; } bool CPowerManager::CanPowerdown() { return m_instance ? m_instance->CanPowerdown() : false; } bool CPowerManager::CanSuspend() { return m_instance ? m_instance->CanSuspend() : false; } bool CPowerManager::CanHibernate() { return m_instance ? m_instance->CanHibernate() : false; } bool CPowerManager::CanReboot() { return m_instance ? m_instance->CanReboot() : false; } int CPowerManager::BatteryLevel() { return m_instance ? m_instance->BatteryLevel() : 0; } void CPowerManager::ProcessEvents() { if (!m_instance) return; static int nesting = 0; if (++nesting == 1) m_instance->PumpPowerEvents(this); nesting--; } void CPowerManager::OnSleep() { CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::System, "OnSleep"); CGUIDialogBusyNoCancel* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_BUSY_NOCANCEL); if (dialog) dialog->Open(); CLog::Log(LOGINFO, "{}: Running sleep jobs", __FUNCTION__); StorePlayerState(); g_application.StopPlaying(); CServiceBroker::GetPVRManager().OnSleep(); auto& components = CServiceBroker::GetAppComponents(); const auto appPower = components.GetComponent(); appPower->StopShutdownTimer(); appPower->StopScreenSaverTimer(); g_application.CloseNetworkShares(); CServiceBroker::GetActiveAE()->Suspend(); } void CPowerManager::OnWake() { CLog::Log(LOGINFO, "{}: Running resume jobs", __FUNCTION__); CServiceBroker::GetNetwork().WaitForNet(); // reset out timers auto& components = CServiceBroker::GetAppComponents(); const auto appPower = components.GetComponent(); appPower->ResetShutdownTimers(); CGUIDialogBusyNoCancel* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_BUSY_NOCANCEL); if (dialog) dialog->Close(true); // force close. no closing animation, sound etc at this early stage #if defined(TARGET_DARWIN_OSX) || defined(TARGET_WINDOWS) if (CServiceBroker::GetWinSystem()->IsFullScreen()) { #if defined(TARGET_WINDOWS_DESKTOP) ShowWindow(g_hWnd, SW_RESTORE); SetForegroundWindow(g_hWnd); #endif } appPower->ResetScreenSaver(); #endif CServiceBroker::GetActiveAE()->Resume(); g_application.UpdateLibraries(); CServiceBroker::GetWeatherManager().Refresh(); CServiceBroker::GetPVRManager().OnWake(); RestorePlayerState(); CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::System, "OnWake"); } void CPowerManager::OnLowBattery() { CLog::Log(LOGINFO, "{}: Running low battery jobs", __FUNCTION__); CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(13050), ""); CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::System, "OnLowBattery"); } void CPowerManager::StorePlayerState() { auto& components = CServiceBroker::GetAppComponents(); const auto appPlayer = components.GetComponent(); if (appPlayer->IsPlaying()) { m_lastUsedPlayer = appPlayer->GetCurrentPlayer(); m_lastPlayedFileItem.reset(new CFileItem(g_application.CurrentFileItem())); // set the actual offset instead of store and load it from database m_lastPlayedFileItem->SetStartOffset(appPlayer->GetTime()); // in case of regular stack, correct the start offset by adding current part start time const auto stackHelper = components.GetComponent(); if (stackHelper->IsPlayingRegularStack()) m_lastPlayedFileItem->SetStartOffset(m_lastPlayedFileItem->GetStartOffset() + stackHelper->GetCurrentStackPartStartTimeMs()); // in case of iso stack, keep track of part number m_lastPlayedFileItem->m_lStartPartNumber = stackHelper->IsPlayingISOStack() ? stackHelper->GetCurrentPartNumber() + 1 : 1; // for iso and iso stacks, keep track of playerstate m_lastPlayedFileItem->SetProperty("savedplayerstate", appPlayer->GetPlayerState()); CLog::Log(LOGDEBUG, "CPowerManager::StorePlayerState - store last played item (startOffset: {} ms)", m_lastPlayedFileItem->GetStartOffset()); } else { m_lastUsedPlayer.clear(); m_lastPlayedFileItem.reset(); } } void CPowerManager::RestorePlayerState() { if (!m_lastPlayedFileItem) return; CLog::Log(LOGDEBUG, "CPowerManager::RestorePlayerState - resume last played item (startOffset: {} ms)", m_lastPlayedFileItem->GetStartOffset()); g_application.PlayFile(*m_lastPlayedFileItem, m_lastUsedPlayer); } void CPowerManager::SettingOptionsShutdownStatesFiller(const SettingConstPtr& setting, std::vector& list, int& current, void* data) { if (CServiceBroker::GetPowerManager().CanPowerdown()) list.emplace_back(g_localizeStrings.Get(13005), POWERSTATE_SHUTDOWN); if (CServiceBroker::GetPowerManager().CanHibernate()) list.emplace_back(g_localizeStrings.Get(13010), POWERSTATE_HIBERNATE); if (CServiceBroker::GetPowerManager().CanSuspend()) list.emplace_back(g_localizeStrings.Get(13011), POWERSTATE_SUSPEND); if (!CServiceBroker::GetAppParams()->IsStandAlone()) { list.emplace_back(g_localizeStrings.Get(13009), POWERSTATE_QUIT); #if !defined(TARGET_DARWIN_EMBEDDED) list.emplace_back(g_localizeStrings.Get(13014), POWERSTATE_MINIMIZE); #endif } }