[droid] Enable external player support
authorMike C <mcrosson_git at nusku dot net>
Thu, 10 Jan 2013 01:22:06 +0000 (20:22 -0500)
committerMike C <mcrosson_git at nusku dot net>
Wed, 23 Jan 2013 20:55:01 +0000 (20:55 +0000)
xbmc/android/activity/XBMCApp.cpp
xbmc/android/activity/XBMCApp.h
xbmc/cores/ExternalPlayer/ExternalPlayer.cpp
xbmc/cores/ExternalPlayer/ExternalPlayer.h

index 94c777b..88139e2 100644 (file)
@@ -730,52 +730,119 @@ bool CXBMCApp::HasLaunchIntent(const string &package)
   return true;
 }
 
-bool CXBMCApp::StartActivity(const string &package)
+// Note intent, dataType, dataURI all default to ""
+bool CXBMCApp::StartActivity(const string &package, const string &intent, const string &dataType, const string &dataURI)
 {
   if (!m_activity || !package.size())
-    return false;
+   return false;
+
+  CLog::Log(LOGDEBUG, "CXBMCApp::StartActivity package: '%s' intent: '%s' dataType: '%s' dataURI: '%s'", package.c_str(), intent.c_str(), dataType.c_str(), dataURI.c_str());
 
   jthrowable exc;
   JNIEnv *env = NULL;
   AttachCurrentThread(&env);
+  
   jobject oActivity = m_activity->clazz;
   jclass cActivity = env->GetObjectClass(oActivity);
 
-  // oPackageManager = new PackageManager();
-  jmethodID mgetPackageManager = env->GetMethodID(cActivity, "getPackageManager", "()Landroid/content/pm/PackageManager;");
-  jobject oPackageManager = (jobject)env->CallObjectMethod(oActivity, mgetPackageManager);
-
-  // oPackageIntent = oPackageManager.getLaunchIntentForPackage(package);
-  jclass cPackageManager = env->GetObjectClass(oPackageManager);
-  jmethodID mgetLaunchIntentForPackage = env->GetMethodID(cPackageManager, "getLaunchIntentForPackage", "(Ljava/lang/String;)Landroid/content/Intent;");
-  jstring sPackageName = env->NewStringUTF(package.c_str());
-  jobject oPackageIntent = env->CallObjectMethod(oPackageManager, mgetLaunchIntentForPackage, sPackageName);
-  env->DeleteLocalRef(cPackageManager);
-  env->DeleteLocalRef(sPackageName);
-  env->DeleteLocalRef(oPackageManager);
+  jobject oIntent = NULL;
+  jclass cIntent = NULL;
+  if (intent.size())
+  {
+    // Java equivalent for following JNI
+    //    Intent oIntent = new Intent(Intent.ACTION_VIEW);
+    cIntent = env->FindClass("android/content/Intent");
+    jmethodID midIntentCtor = env->GetMethodID(cIntent, "<init>", "(Ljava/lang/String;)V");
+    jstring sIntent = env->NewStringUTF(intent.c_str());
+    oIntent = env->NewObject(cIntent, midIntentCtor, sIntent);
+    env->DeleteLocalRef(sIntent);
+  }
+  else
+  {
+    // oPackageManager = new PackageManager();
+    jmethodID mgetPackageManager = env->GetMethodID(cActivity, "getPackageManager", "()Landroid/content/pm/PackageManager;");
+    jobject oPackageManager = (jobject)env->CallObjectMethod(oActivity, mgetPackageManager);
+
+    // oPackageIntent = oPackageManager.getLaunchIntentForPackage(package);
+    jclass cPackageManager = env->GetObjectClass(oPackageManager);
+    jmethodID mgetLaunchIntentForPackage = env->GetMethodID(cPackageManager, "getLaunchIntentForPackage", "(Ljava/lang/String;)Landroid/content/Intent;");
+    jstring sPackageName = env->NewStringUTF(package.c_str());
+    oIntent = env->CallObjectMethod(oPackageManager, mgetLaunchIntentForPackage, sPackageName);
+    cIntent = env->GetObjectClass(oIntent);
+    env->DeleteLocalRef(cPackageManager);
+    env->DeleteLocalRef(sPackageName);
+    env->DeleteLocalRef(oPackageManager);
+
+    exc = env->ExceptionOccurred();
+    if (exc)
+    {
+      CLog::Log(LOGERROR, "CXBMCApp::StartActivity Failed to load %s. Exception follows:", package.c_str());
+      env->ExceptionDescribe();
+      env->ExceptionClear();
+      env->DeleteLocalRef(cActivity);
+      DetachCurrentThread();
+      return false;
+    }
+    if (!oIntent)
+    {
+      CLog::Log(LOGERROR, "CXBMCApp::StartActivity %s has no Launch Intent", package.c_str());
+      env->DeleteLocalRef(cActivity);
+      DetachCurrentThread();
+      return false;
+    }
+  }
 
-  exc = env->ExceptionOccurred();
-  if (exc)
+  jobject oUri;
+  if (dataURI.size())
   {
-    CLog::Log(LOGERROR, "CXBMCApp::StartActivity Failed to load %s. Exception follows:", package.c_str());
-    env->ExceptionDescribe();
-    env->ExceptionClear();
-    env->DeleteLocalRef(cActivity);
-    DetachCurrentThread();
-    return false;
+    // Java equivalent for the following JNI
+    //   Uri oUri = Uri.parse(sPath);
+    jclass cUri = env->FindClass("android/net/Uri");
+    jmethodID midUriParse = env->GetStaticMethodID(cUri, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
+    jstring sPath = env->NewStringUTF(dataURI.c_str());
+    oUri = env->CallStaticObjectMethod(cUri, midUriParse, sPath);
+    env->DeleteLocalRef(sPath);
+    env->DeleteLocalRef(cUri);
+
+    // Run setData or setDataAndType depending on what was passed into the method
+    //   This allows opening market links or external players using the same method
+    if (dataType.size())
+    {
+      // Java equivalent for the following JNI
+      //   oIntent.setDataAndType(oUri, "video/*");
+      jmethodID midIntentSetDataAndType = env->GetMethodID(cIntent, "setDataAndType", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;");
+      jstring sMimeType = env->NewStringUTF(dataType.c_str());
+      oIntent = env->CallObjectMethod(oIntent, midIntentSetDataAndType, oUri, sMimeType);
+      env->DeleteLocalRef(sMimeType);
+    }
+    else 
+    {
+      // Java equivalent for the following JNI
+      //   oIntent.setData(oUri);
+      jmethodID midIntentSetData = env->GetMethodID(cIntent, "setData", "(Landroid/net/Uri;)Landroid/content/Intent;");
+      oIntent = env->CallObjectMethod(oIntent, midIntentSetData, oUri);
+    }
   }
-  if (!oPackageIntent)
+  
+  // Java equivalent for the following JNI
+  //   oIntent.setPackage(sPackage);
+  jstring sPackage = env->NewStringUTF(package.c_str());
+  jmethodID mSetPackage = env->GetMethodID(cIntent, "setPackage", "(Ljava/lang/String;)Landroid/content/Intent;");
+  oIntent = env->CallObjectMethod(oIntent, mSetPackage, sPackage);
+
+  if (oUri != NULL)
   {
-    CLog::Log(LOGERROR, "CXBMCApp::StartActivity %s has no Launch Intent", package.c_str());
-    env->DeleteLocalRef(cActivity);
-    DetachCurrentThread();
-    return false;
+    env->DeleteLocalRef(oUri);
   }
-  // startActivity(oIntent);
+  env->DeleteLocalRef(cIntent);
+  env->DeleteLocalRef(sPackage);
+  // Java equivalent for the following JNI
+  //   startActivity(oIntent);
   jmethodID mStartActivity = env->GetMethodID(cActivity, "startActivity", "(Landroid/content/Intent;)V");
-  env->CallVoidMethod(oActivity, mStartActivity, oPackageIntent);
+  env->CallVoidMethod(oActivity, mStartActivity, oIntent);
   env->DeleteLocalRef(cActivity);
-  env->DeleteLocalRef(oPackageIntent);
+  env->DeleteLocalRef(oIntent);
 
   exc = env->ExceptionOccurred();
   if (exc)
index 4bf2d2e..b08b6df 100644 (file)
@@ -83,7 +83,7 @@ public:
   static int android_printf(const char *format, ...);
   
   static int GetBatteryLevel();
-  static bool StartActivity(const std::string &package);
+  static bool StartActivity(const std::string &package, const std::string &intent = std::string(), const std::string &dataType = std::string(), const std::string &dataURI = std::string());
   static bool ListApplications(std::vector <androidPackage> *applications);
   static bool GetIconSize(const std::string &packageName, int *width, int *height);
   static bool GetIcon(const std::string &packageName, void* buffer, unsigned int bufSize); 
index 38261d4..646be86 100644 (file)
@@ -47,6 +47,9 @@
 #if defined(HAS_LIRC)
   #include "input/linux/LIRC.h"
 #endif
+#if defined(TARGET_ANDROID)
+  #include "android/activity/XBMCApp.h"
+#endif
 
 // If the process ends in less than this time (ms), we assume it's a launcher
 // and wait for manual intervention before continuing
@@ -311,6 +314,8 @@ void CExternalPlayer::Process()
   BOOL ret = TRUE;
 #if defined(_WIN32)
   ret = ExecuteAppW32(strFName.c_str(),strFArgs.c_str());
+#elif defined(TARGET_ANDROID)
+  ret = ExecuteAppAndroid(m_filename.c_str(), mainFile.c_str());
 #elif defined(_LINUX) || defined(TARGET_DARWIN_OSX)
   ret = ExecuteAppLinux(strFArgs.c_str());
 #endif
@@ -443,7 +448,7 @@ BOOL CExternalPlayer::ExecuteAppW32(const char* strPath, const char* strSwitches
 }
 #endif
 
-#if defined(_LINUX) || defined(TARGET_DARWIN_OSX)
+#if !defined(TARGET_ANDROID) && (defined(_LINUX) || defined(TARGET_DARWIN_OSX))
 BOOL CExternalPlayer::ExecuteAppLinux(const char* strSwitches)
 {
   CLog::Log(LOGNOTICE, "%s: %s", __FUNCTION__, strSwitches);
@@ -469,6 +474,22 @@ BOOL CExternalPlayer::ExecuteAppLinux(const char* strSwitches)
 }
 #endif
 
+#if defined(TARGET_ANDROID)
+BOOL CExternalPlayer::ExecuteAppAndroid(const char* strSwitches,const char* strPath)
+{
+  CLog::Log(LOGNOTICE, "%s: %s", __FUNCTION__, strSwitches);
+
+  int ret = CXBMCApp::StartActivity(strSwitches, "android.intent.action.VIEW", "video/*", strPath);
+
+  if (ret != 0)
+  {
+    CLog::Log(LOGNOTICE, "%s: Failure: %d", __FUNCTION__, ret);
+  }
+
+  return ret == 0;
+}
+#endif
+
 void CExternalPlayer::Pause()
 {
 }
index ee0b898..4221564 100644 (file)
@@ -82,6 +82,8 @@ public:
 #if defined(_WIN32)
   virtual BOOL ExecuteAppW32(const char* strPath, const char* strSwitches);
   //static void CALLBACK AppFinished(void* closure, BOOLEAN TimerOrWaitFired);
+#elif defined(TARGET_ANDROID)
+  virtual BOOL ExecuteAppAndroid(const char* strSwitches,const char* strPath);
 #elif defined(_LINUX)
   virtual BOOL ExecuteAppLinux(const char* strSwitches);
 #endif