1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "PVRGUIActionListener.h"
10
11 #include "Application.h"
12 #include "ServiceBroker.h"
13 #include "dialogs/GUIDialogNumeric.h"
14 #include "guilib/GUIComponent.h"
15 #include "guilib/GUIWindowManager.h"
16 #include "guilib/WindowIDs.h"
17 #include "input/actions/Action.h"
18 #include "input/actions/ActionIDs.h"
19 #include "messaging/ApplicationMessenger.h"
20 #include "pvr/PVRManager.h"
21 #include "pvr/PVRPlaybackState.h"
22 #include "pvr/addons/PVRClients.h"
23 #include "pvr/channels/PVRChannel.h"
24 #include "pvr/channels/PVRChannelGroup.h"
25 #include "pvr/channels/PVRChannelGroups.h"
26 #include "pvr/channels/PVRChannelGroupsContainer.h"
27 #include "pvr/guilib/PVRGUIActions.h"
28 #include "settings/Settings.h"
29 #include "settings/SettingsComponent.h"
30 #include "settings/lib/Setting.h"
31
32 #include <memory>
33 #include <string>
34
35 namespace PVR
36 {
37
CPVRGUIActionListener()38 CPVRGUIActionListener::CPVRGUIActionListener()
39 {
40 g_application.RegisterActionListener(this);
41 CServiceBroker::GetSettingsComponent()->GetSettings()->RegisterCallback(this, {
42 CSettings::SETTING_PVRPARENTAL_ENABLED,
43 CSettings::SETTING_PVRMANAGER_RESETDB,
44 CSettings::SETTING_EPG_RESETEPG,
45 CSettings::SETTING_PVRMANAGER_CLIENTPRIORITIES,
46 CSettings::SETTING_PVRMANAGER_CHANNELMANAGER,
47 CSettings::SETTING_PVRMANAGER_GROUPMANAGER,
48 CSettings::SETTING_PVRMANAGER_CHANNELSCAN,
49 CSettings::SETTING_PVRMENU_SEARCHICONS,
50 CSettings::SETTING_PVRCLIENT_MENUHOOK,
51 CSettings::SETTING_EPG_PAST_DAYSTODISPLAY,
52 CSettings::SETTING_EPG_FUTURE_DAYSTODISPLAY
53 });
54 }
55
~CPVRGUIActionListener()56 CPVRGUIActionListener::~CPVRGUIActionListener()
57 {
58 CServiceBroker::GetSettingsComponent()->GetSettings()->UnregisterCallback(this);
59 g_application.UnregisterActionListener(this);
60 }
61
Init(CPVRManager & mgr)62 void CPVRGUIActionListener::Init(CPVRManager& mgr)
63 {
64 mgr.Events().Subscribe(this, &CPVRGUIActionListener::OnPVRManagerEvent);
65 }
66
Deinit(CPVRManager & mgr)67 void CPVRGUIActionListener::Deinit(CPVRManager& mgr)
68 {
69 mgr.Events().Unsubscribe(this);
70 }
71
OnPVRManagerEvent(const PVREvent & event)72 void CPVRGUIActionListener::OnPVRManagerEvent(const PVREvent& event)
73 {
74 if (event == PVREvent::AnnounceReminder)
75 {
76 if (g_application.IsInitialized())
77 {
78 // if GUI is ready, dispatch to GUI thread and handle the action there
79 KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(
80 TMSG_GUI_ACTION, WINDOW_INVALID, -1,
81 static_cast<void*>(new CAction(ACTION_PVR_ANNOUNCE_REMINDERS)));
82 }
83 }
84 }
85
GetChannelSwitchMode(int iAction)86 ChannelSwitchMode CPVRGUIActionListener::GetChannelSwitchMode(int iAction)
87 {
88 if ((iAction == ACTION_MOVE_UP || iAction == ACTION_MOVE_DOWN) &&
89 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRPLAYBACK_CONFIRMCHANNELSWITCH))
90 return ChannelSwitchMode::NO_SWITCH;
91
92 return ChannelSwitchMode::INSTANT_OR_DELAYED_SWITCH;
93 }
94
OnAction(const CAction & action)95 bool CPVRGUIActionListener::OnAction(const CAction& action)
96 {
97 bool bIsJumpSMS = false;
98 bool bIsPlayingPVR = CServiceBroker::GetPVRManager().PlaybackState()->IsPlaying() &&
99 g_application.CurrentFileItem().HasPVRChannelInfoTag();
100
101 switch (action.GetID())
102 {
103 case ACTION_PVR_PLAY:
104 case ACTION_PVR_PLAY_TV:
105 case ACTION_PVR_PLAY_RADIO:
106 {
107 // see if we're already playing a PVR stream and if not or the stream type
108 // doesn't match the demanded type, start playback of according type
109 switch (action.GetID())
110 {
111 case ACTION_PVR_PLAY:
112 if (!bIsPlayingPVR)
113 CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(PlaybackTypeAny);
114 break;
115 case ACTION_PVR_PLAY_TV:
116 if (!bIsPlayingPVR || g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio())
117 CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(PlaybackTypeTV);
118 break;
119 case ACTION_PVR_PLAY_RADIO:
120 if (!bIsPlayingPVR || !g_application.CurrentFileItem().GetPVRChannelInfoTag()->IsRadio())
121 CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(PlaybackTypeRadio);
122 break;
123 }
124 return true;
125 }
126
127 case ACTION_JUMP_SMS2:
128 case ACTION_JUMP_SMS3:
129 case ACTION_JUMP_SMS4:
130 case ACTION_JUMP_SMS5:
131 case ACTION_JUMP_SMS6:
132 case ACTION_JUMP_SMS7:
133 case ACTION_JUMP_SMS8:
134 case ACTION_JUMP_SMS9:
135 bIsJumpSMS = true;
136 // fallthru is intended
137 case REMOTE_0:
138 case REMOTE_1:
139 case REMOTE_2:
140 case REMOTE_3:
141 case REMOTE_4:
142 case REMOTE_5:
143 case REMOTE_6:
144 case REMOTE_7:
145 case REMOTE_8:
146 case REMOTE_9:
147 case ACTION_CHANNEL_NUMBER_SEP:
148 {
149 if (!bIsPlayingPVR)
150 return false;
151
152 if (CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_FULLSCREEN_VIDEO) || CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_VISUALISATION))
153 {
154 // do not consume action if a python modal is the top most dialog
155 // as a python modal can't return that it consumed the action.
156 if (CServiceBroker::GetGUI()->GetWindowManager().IsPythonWindow(CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog()))
157 return false;
158
159 char cCharacter;
160 if (action.GetID() == ACTION_CHANNEL_NUMBER_SEP)
161 {
162 cCharacter = CPVRChannelNumber::SEPARATOR;
163 }
164 else
165 {
166 int iRemote = bIsJumpSMS ? action.GetID() - (ACTION_JUMP_SMS2 - REMOTE_2) : action.GetID();
167 cCharacter = (iRemote - REMOTE_0) + '0';
168 }
169 CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().AppendChannelNumberCharacter(cCharacter);
170 return true;
171 }
172 return false;
173 }
174
175 case ACTION_SHOW_INFO:
176 {
177 if (!bIsPlayingPVR)
178 return false;
179
180 CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().ToggleInfo();
181 return true;
182 }
183
184 case ACTION_SELECT_ITEM:
185 {
186 if (!bIsPlayingPVR)
187 return false;
188
189 // If the button that caused this action matches action "Select" ...
190 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRPLAYBACK_CONFIRMCHANNELSWITCH) &&
191 CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().IsPreview())
192 {
193 // ... and if "confirm channel switch" setting is active and a channel
194 // preview is currently shown, switch to the currently previewed channel.
195 CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().SwitchToCurrentChannel();
196 return true;
197 }
198 else if (CServiceBroker::GetPVRManager().GUIActions()->GetChannelNumberInputHandler().CheckInputAndExecuteAction())
199 {
200 // ... or if the action was processed by direct channel number input, we're done.
201 return true;
202 }
203 return false;
204 }
205
206 case ACTION_NEXT_ITEM:
207 {
208 if (!bIsPlayingPVR)
209 return false;
210
211 CServiceBroker::GetPVRManager().GUIActions()->SeekForward();
212 return true;
213 }
214
215 case ACTION_PREV_ITEM:
216 {
217 if (!bIsPlayingPVR)
218 return false;
219
220 CServiceBroker::GetPVRManager().GUIActions()->SeekBackward(CApplication::ACTION_PREV_ITEM_THRESHOLD);
221 return true;
222 }
223
224 case ACTION_MOVE_UP:
225 case ACTION_CHANNEL_UP:
226 {
227 if (!bIsPlayingPVR)
228 return false;
229
230 CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().SelectNextChannel(GetChannelSwitchMode(action.GetID()));
231 return true;
232 }
233
234 case ACTION_MOVE_DOWN:
235 case ACTION_CHANNEL_DOWN:
236 {
237 if (!bIsPlayingPVR)
238 return false;
239
240 CServiceBroker::GetPVRManager().GUIActions()->GetChannelNavigator().SelectPreviousChannel(GetChannelSwitchMode(action.GetID()));
241 return true;
242 }
243
244 case ACTION_CHANNEL_SWITCH:
245 {
246 if (!bIsPlayingPVR)
247 return false;
248
249 int iChannelNumber = static_cast<int>(action.GetAmount(0));
250 int iSubChannelNumber = static_cast<int>(action.GetAmount(1));
251
252 const std::shared_ptr<CPVRChannel> currentChannel = CServiceBroker::GetPVRManager().PlaybackState()->GetPlayingChannel();
253 const std::shared_ptr<CPVRChannelGroup> selectedGroup = CServiceBroker::GetPVRManager().ChannelGroups()->Get(currentChannel->IsRadio())->GetSelectedGroup();
254 const std::shared_ptr<CPVRChannel> channel = selectedGroup->GetByChannelNumber(CPVRChannelNumber(iChannelNumber, iSubChannelNumber));
255
256 if (!channel)
257 return false;
258
259 CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(std::make_shared<CFileItem>(channel), false);
260 return true;
261 }
262
263 case ACTION_RECORD:
264 {
265 CServiceBroker::GetPVRManager().GUIActions()->ToggleRecordingOnPlayingChannel();
266 return true;
267 }
268
269 case ACTION_PVR_ANNOUNCE_REMINDERS:
270 {
271 CServiceBroker::GetPVRManager().GUIActions()->AnnounceReminders();
272 return true;
273 }
274 }
275 return false;
276 }
277
OnSettingChanged(const std::shared_ptr<const CSetting> & setting)278 void CPVRGUIActionListener::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
279 {
280 if (setting == nullptr)
281 return;
282
283 const std::string& settingId = setting->GetId();
284 if (settingId == CSettings::SETTING_PVRPARENTAL_ENABLED)
285 {
286 if (std::static_pointer_cast<const CSettingBool>(setting)->GetValue() && CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_PVRPARENTAL_PIN).empty())
287 {
288 std::string newPassword = "";
289 // password set... save it
290 if (CGUIDialogNumeric::ShowAndVerifyNewPassword(newPassword))
291 CServiceBroker::GetSettingsComponent()->GetSettings()->SetString(CSettings::SETTING_PVRPARENTAL_PIN, newPassword);
292 // password not set... disable parental
293 else
294 std::static_pointer_cast<CSettingBool>(std::const_pointer_cast<CSetting>(setting))->SetValue(false);
295 }
296 }
297 else if (settingId == CSettings::SETTING_EPG_PAST_DAYSTODISPLAY)
298 {
299 CServiceBroker::GetPVRManager().Clients()->SetEPGMaxPastDays(
300 std::static_pointer_cast<const CSettingInt>(setting)->GetValue());
301 }
302 else if (settingId == CSettings::SETTING_EPG_FUTURE_DAYSTODISPLAY)
303 {
304 CServiceBroker::GetPVRManager().Clients()->SetEPGMaxFutureDays(
305 std::static_pointer_cast<const CSettingInt>(setting)->GetValue());
306 }
307 }
308
OnSettingAction(const std::shared_ptr<const CSetting> & setting)309 void CPVRGUIActionListener::OnSettingAction(const std::shared_ptr<const CSetting>& setting)
310 {
311 if (setting == nullptr)
312 return;
313
314 const std::string& settingId = setting->GetId();
315 if (settingId == CSettings::SETTING_PVRMANAGER_RESETDB)
316 {
317 CServiceBroker::GetPVRManager().GUIActions()->ResetPVRDatabase(false);
318 }
319 else if (settingId == CSettings::SETTING_EPG_RESETEPG)
320 {
321 CServiceBroker::GetPVRManager().GUIActions()->ResetPVRDatabase(true);
322 }
323 else if (settingId == CSettings::SETTING_PVRMANAGER_CLIENTPRIORITIES)
324 {
325 if (CServiceBroker::GetPVRManager().IsStarted())
326 {
327 CGUIDialog* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_CLIENT_PRIORITIES);
328 if (dialog)
329 {
330 dialog->Open();
331 CServiceBroker::GetPVRManager().ChannelGroups()->Update();
332 }
333 }
334 }
335 else if (settingId == CSettings::SETTING_PVRMANAGER_CHANNELMANAGER)
336 {
337 if (CServiceBroker::GetPVRManager().IsStarted())
338 {
339 CGUIDialog* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_CHANNEL_MANAGER);
340 if (dialog)
341 dialog->Open();
342 }
343 }
344 else if (settingId == CSettings::SETTING_PVRMANAGER_GROUPMANAGER)
345 {
346 if (CServiceBroker::GetPVRManager().IsStarted())
347 {
348 CGUIDialog* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetDialog(WINDOW_DIALOG_PVR_GROUP_MANAGER);
349 if (dialog)
350 dialog->Open();
351 }
352 }
353 else if (settingId == CSettings::SETTING_PVRMANAGER_CHANNELSCAN)
354 {
355 CServiceBroker::GetPVRManager().GUIActions()->StartChannelScan();
356 }
357 else if (settingId == CSettings::SETTING_PVRMENU_SEARCHICONS)
358 {
359 CServiceBroker::GetPVRManager().TriggerSearchMissingChannelIcons();
360 }
361 else if (settingId == CSettings::SETTING_PVRCLIENT_MENUHOOK)
362 {
363 CServiceBroker::GetPVRManager().GUIActions()->ProcessSettingsMenuHooks();
364 }
365 }
366
367 } // namespace PVR
368