1 /*
2  *  Copyright (C) 2017 Christian Browet
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 "JNIXBMCMediaSession.h"
10 
11 #include "AndroidKey.h"
12 #include "Application.h"
13 #include "CompileInfo.h"
14 #include "XBMCApp.h"
15 #include "input/Key.h"
16 #include "messaging/ApplicationMessenger.h"
17 
18 #include <androidjni/Context.h>
19 #include <androidjni/KeyEvent.h>
20 #include <androidjni/jutils-details.hpp>
21 
22 using namespace jni;
23 
24 static std::string s_className = std::string(CCompileInfo::GetClass()) + "/XBMCMediaSession";
25 
CJNIXBMCMediaSession()26 CJNIXBMCMediaSession::CJNIXBMCMediaSession()
27   : CJNIBase(s_className)
28 {
29   m_object = new_object(CJNIContext::getClassLoader().loadClass(GetDotClassName(s_className)));
30   m_object.setGlobal();
31 
32   add_instance(m_object, this);
33 }
34 
CJNIXBMCMediaSession(const CJNIXBMCMediaSession & other)35 CJNIXBMCMediaSession::CJNIXBMCMediaSession(const CJNIXBMCMediaSession& other)
36   : CJNIBase(other)
37 {
38   add_instance(m_object, this);
39 }
40 
~CJNIXBMCMediaSession()41 CJNIXBMCMediaSession::~CJNIXBMCMediaSession()
42 {
43   remove_instance(this);
44 }
45 
RegisterNatives(JNIEnv * env)46 void CJNIXBMCMediaSession::RegisterNatives(JNIEnv* env)
47 {
48   jclass cClass = env->FindClass(s_className.c_str());
49   if(cClass)
50   {
51     JNINativeMethod methods[] =
52     {
53       {"_onPlayRequested", "()V", (void*)&CJNIXBMCMediaSession::_onPlayRequested},
54       {"_onPauseRequested", "()V", (void*)&CJNIXBMCMediaSession::_onPauseRequested},
55       {"_onNextRequested", "()V", (void*)&CJNIXBMCMediaSession::_onNextRequested},
56       {"_onPreviousRequested", "()V", (void*)&CJNIXBMCMediaSession::_onPreviousRequested},
57       {"_onForwardRequested", "()V", (void*)&CJNIXBMCMediaSession::_onForwardRequested},
58       {"_onRewindRequested", "()V", (void*)&CJNIXBMCMediaSession::_onRewindRequested},
59       {"_onStopRequested", "()V", (void*)&CJNIXBMCMediaSession::_onStopRequested},
60       {"_onSeekRequested", "(J)V", (void*)&CJNIXBMCMediaSession::_onSeekRequested},
61       {"_onMediaButtonEvent", "(Landroid/content/Intent;)Z", (void*)&CJNIXBMCMediaSession::_onMediaButtonEvent},
62     };
63 
64     env->RegisterNatives(cClass, methods, sizeof(methods)/sizeof(methods[0]));
65   }
66 }
67 
activate(bool state)68 void CJNIXBMCMediaSession::activate(bool state)
69 {
70   if (state == m_isActive)
71     return;
72 
73   call_method<void>(m_object,
74                     "activate", "(Z)V",
75                     (jboolean)state);
76   m_isActive = state;
77 }
78 
updatePlaybackState(const CJNIPlaybackState & state)79 void CJNIXBMCMediaSession::updatePlaybackState(const CJNIPlaybackState& state)
80 {
81   call_method<void>(m_object,
82                     "updatePlaybackState", "(Landroid/media/session/PlaybackState;)V",
83                     state.get_raw());
84 }
85 
updateMetadata(const CJNIMediaMetadata & myData)86 void CJNIXBMCMediaSession::updateMetadata(const CJNIMediaMetadata& myData)
87 {
88   call_method<void>(m_object,
89                     "updateMetadata", "(Landroid/media/MediaMetadata;)V",
90                     myData.get_raw());
91 }
92 
updateIntent(const CJNIIntent & intent)93 void CJNIXBMCMediaSession::updateIntent(const CJNIIntent& intent)
94 {
95   call_method<void>(m_object,
96                     "updateIntent", "(Landroid/content/Intent;)V",
97                     intent.get_raw());
98 }
99 
OnPlayRequested()100 void CJNIXBMCMediaSession::OnPlayRequested()
101 {
102   if (g_application.GetAppPlayer().IsPlaying())
103   {
104     if (g_application.GetAppPlayer().IsPaused())
105       KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_PAUSE)));
106   }
107 }
108 
OnPauseRequested()109 void CJNIXBMCMediaSession::OnPauseRequested()
110 {
111   if (g_application.GetAppPlayer().IsPlaying())
112   {
113     if (!g_application.GetAppPlayer().IsPaused())
114       KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_PAUSE)));
115   }
116 }
117 
OnNextRequested()118 void CJNIXBMCMediaSession::OnNextRequested()
119 {
120   if (g_application.GetAppPlayer().IsPlaying())
121     KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_NEXT_ITEM)));
122 }
123 
OnPreviousRequested()124 void CJNIXBMCMediaSession::OnPreviousRequested()
125 {
126   if (g_application.GetAppPlayer().IsPlaying())
127     KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_PREV_ITEM)));
128 }
129 
OnForwardRequested()130 void CJNIXBMCMediaSession::OnForwardRequested()
131 {
132   if (g_application.GetAppPlayer().IsPlaying())
133   {
134     if (!g_application.GetAppPlayer().IsPaused())
135       KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_PLAYER_FORWARD)));
136   }
137 }
138 
OnRewindRequested()139 void CJNIXBMCMediaSession::OnRewindRequested()
140 {
141   if (g_application.GetAppPlayer().IsPlaying())
142   {
143     if (!g_application.GetAppPlayer().IsPaused())
144       KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_PLAYER_REWIND)));
145   }
146 }
147 
OnStopRequested()148 void CJNIXBMCMediaSession::OnStopRequested()
149 {
150   if (g_application.GetAppPlayer().IsPlaying())
151     KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_GUI_ACTION, WINDOW_INVALID, -1, static_cast<void*>(new CAction(ACTION_STOP)));
152 }
153 
OnSeekRequested(int64_t pos)154 void CJNIXBMCMediaSession::OnSeekRequested(int64_t pos)
155 {
156   g_application.SeekTime(pos / 1000.0);
157 }
158 
OnMediaButtonEvent(const CJNIIntent & intent)159 bool CJNIXBMCMediaSession::OnMediaButtonEvent(const CJNIIntent& intent)
160 {
161   if (CXBMCApp::HasFocus())
162   {
163     CXBMCApp::get()->onReceive(intent);
164     return true;
165   }
166   return false;
167 }
168 
isActive() const169 bool CJNIXBMCMediaSession::isActive() const
170 {
171   return m_isActive;
172 }
173 
174 /**********************/
175 
_onPlayRequested(JNIEnv * env,jobject thiz)176 void CJNIXBMCMediaSession::_onPlayRequested(JNIEnv* env, jobject thiz)
177 {
178   (void)env;
179 
180   CJNIXBMCMediaSession *inst = find_instance(thiz);
181   if (inst)
182     inst->OnPlayRequested();
183 }
184 
_onPauseRequested(JNIEnv * env,jobject thiz)185 void CJNIXBMCMediaSession::_onPauseRequested(JNIEnv* env, jobject thiz)
186 {
187   (void)env;
188 
189   CJNIXBMCMediaSession *inst = find_instance(thiz);
190   if (inst)
191     inst->OnPauseRequested();
192 }
193 
_onNextRequested(JNIEnv * env,jobject thiz)194 void CJNIXBMCMediaSession::_onNextRequested(JNIEnv* env, jobject thiz)
195 {
196   (void)env;
197 
198   CJNIXBMCMediaSession *inst = find_instance(thiz);
199   if (inst)
200     inst->OnNextRequested();
201 }
202 
_onPreviousRequested(JNIEnv * env,jobject thiz)203 void CJNIXBMCMediaSession::_onPreviousRequested(JNIEnv* env, jobject thiz)
204 {
205   (void)env;
206 
207   CJNIXBMCMediaSession *inst = find_instance(thiz);
208   if (inst)
209     inst->OnPreviousRequested();
210 }
211 
_onForwardRequested(JNIEnv * env,jobject thiz)212 void CJNIXBMCMediaSession::_onForwardRequested(JNIEnv* env, jobject thiz)
213 {
214   (void)env;
215 
216   CJNIXBMCMediaSession *inst = find_instance(thiz);
217   if (inst)
218     inst->OnForwardRequested();
219 }
220 
_onRewindRequested(JNIEnv * env,jobject thiz)221 void CJNIXBMCMediaSession::_onRewindRequested(JNIEnv* env, jobject thiz)
222 {
223   (void)env;
224 
225   CJNIXBMCMediaSession *inst = find_instance(thiz);
226   if (inst)
227     inst->OnRewindRequested();
228 }
229 
_onStopRequested(JNIEnv * env,jobject thiz)230 void CJNIXBMCMediaSession::_onStopRequested(JNIEnv* env, jobject thiz)
231 {
232   (void)env;
233 
234   CJNIXBMCMediaSession *inst = find_instance(thiz);
235   if (inst)
236     inst->OnStopRequested();
237 }
238 
_onSeekRequested(JNIEnv * env,jobject thiz,jlong pos)239 void CJNIXBMCMediaSession::_onSeekRequested(JNIEnv* env, jobject thiz, jlong pos)
240 {
241   (void)env;
242 
243   CJNIXBMCMediaSession *inst = find_instance(thiz);
244   if (inst)
245     inst->OnSeekRequested(pos);
246 }
247 
_onMediaButtonEvent(JNIEnv * env,jobject thiz,jobject intent)248 bool CJNIXBMCMediaSession::_onMediaButtonEvent(JNIEnv* env, jobject thiz, jobject intent)
249 {
250   (void)env;
251 
252   CJNIXBMCMediaSession *inst = find_instance(thiz);
253   if (inst)
254     return inst->OnMediaButtonEvent(CJNIIntent(jhobject::fromJNI(intent)));
255   return false;
256 }
257 
258