Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

ADD: [droid] Register XBMC as media player #2381

Closed
wants to merge 1 commit into from

2 participants

@koying
Collaborator

This is an initial attempt at registering XBMC as a media player on droid.

To be discussed, ofc

@theuni theuni was assigned
@koying
Collaborator

whitespace issue, going from tabs to blanks. You can use https://github.com/xbmc/xbmc/pull/2381/files?w=1 to ignore them, or I can revert, if you prefer

@theuni
Owner

Yea, please keep cosmetics in separate commits.

@theuni
Owner

Since you've created a nice Main class, could you please move the startup logic into there and out of Splash? I think that should detangle the startup process a good bit.

@koying
Collaborator

Re Main vs. Splash, it indeed makes sense to put the caching stuff there...

@theuni
Owner

ok to push this to next month?

@koying
Collaborator
@theuni
Owner

This should be obsolete now. Simply test the intent using the android api now, see here: https://github.com/xbmc/xbmc/blob/master/xbmc/android/activity/XBMCApp.cpp#L236

@theuni theuni referenced this pull request
Merged

Android register player #2746

@ghost

anything left of value here? if so, please reopen.

@ghost ghost closed this
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 12, 2013
  1. @koying
This page is out of date. Refresh to see the latest.
View
25 tools/android/packaging/xbmc/AndroidManifest.xml
@@ -25,6 +25,31 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data android:mimeType="video/*" />
+ <data android:mimeType="audio/*" />
+
+ <data android:scheme="file" />
+ <data android:scheme="content" />
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:scheme="ftp" />
+ <data android:scheme="ftps" />
+ <data android:scheme="rtp" />
+ <data android:scheme="rtsp" />
+ <data android:scheme="mms" />
+ <data android:scheme="dav" />
+ <data android:scheme="davs" />
+ <data android:scheme="ssh" />
+ <data android:scheme="sftp" />
+ <data android:scheme="smb" />
+
+ </intent-filter>
</activity>
<!--
View
11 tools/android/packaging/xbmc/src/org/xbmc/xbmc/Main.java
@@ -6,6 +6,8 @@
public class Main extends NativeActivity
{
+ native void ReceiveViewIntent(Intent intent);
+
public Main()
{
super();
@@ -16,4 +18,13 @@ public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
+
+ @Override
+ protected void onNewIntent(Intent intent)
+ {
+ super.onNewIntent(intent);
+
+ if (intent.getAction() == Intent.ACTION_VIEW)
+ ReceiveViewIntent(intent);
+ }
}
View
34 tools/android/packaging/xbmc/src/org/xbmc/xbmc/Splash.java
@@ -13,6 +13,8 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import android.database.Cursor;
+import android.provider.MediaStore.MediaColumns;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
@@ -22,6 +24,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.net.Uri;
import android.util.Log;
import android.text.Html;
import android.text.method.LinkMovementMethod;
@@ -236,10 +239,35 @@ private boolean CheckCpuFeature(String feat) {
}
protected void startXBMC() {
+ Intent xbmcIntent = new Intent();
+ xbmcIntent.setClass(this, org.xbmc.xbmc.Main.class);
+
+ // Check incoming intent
+ Intent intent = getIntent();
+ String action = intent.getAction();
+
+ if (action.equals(Intent.ACTION_VIEW)) {
+ Uri data = intent.getData();
+ Log.i(TAG, "Incoming Uri: " + data.toString());
+
+ // Translate "content://" uri's to "file://" ones
+ if (data.getScheme().equalsIgnoreCase("content"))
+ {
+ String[] filePathColumn = {MediaColumns.DATA};
+ Cursor cursor = getContentResolver().query(data, filePathColumn, null, null, null);
+ if(cursor.moveToFirst())
+ {
+ int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
+ data = Uri.parse(cursor.getString(columnIndex));
+ }
+ cursor.close();
+ }
+ xbmcIntent.setAction(Intent.ACTION_VIEW);
+ xbmcIntent.setData(data);
+ }
+
// Run XBMC
- Intent intent = new Intent();
- intent.setClass(this, org.xbmc.xbmc.Main.class);
- startActivity(intent);
+ startActivity(xbmcIntent);
finish();
}
View
4 xbmc/android/activity/BroadcastReceiver.cpp
@@ -23,7 +23,7 @@
CBroadcastReceiver::CBroadcastReceiver() : CAndroidJNIBase("org/xbmc/xbmc/XBMCBroadcastReceiver")
{
- AddMethod(jniNativeMethod("ReceiveIntent", "(Landroid/content/Intent;)V", (void*)jni_ReceiveIntent));
+ AddMethod(jniNativeMethod("ReceiveIntent", "(Landroid/content/Intent;)V", (void*)jni_BroadcastReceiverReceiveIntent));
}
void CBroadcastReceiver::ReceiveIntent(JNIEnv *env, jobject thiz, jobject intent)
@@ -31,7 +31,7 @@ void CBroadcastReceiver::ReceiveIntent(JNIEnv *env, jobject thiz, jobject intent
CAndroidIntents::getInstance().ReceiveIntent(env, intent);
}
-void jni_ReceiveIntent(JNIEnv *env, jobject thiz, jobject intent)
+void jni_BroadcastReceiverReceiveIntent(JNIEnv *env, jobject thiz, jobject intent)
{
CAndroidJNIManager::GetInstance().GetBroadcastReceiver()->ReceiveIntent(env, thiz, intent);
}
View
2  xbmc/android/activity/BroadcastReceiver.h
@@ -31,4 +31,4 @@ friend class CAndroidJNIManager;
CBroadcastReceiver();
};
-extern "C" void jni_ReceiveIntent(JNIEnv *env, jobject thiz, jobject intent);
+extern "C" void jni_BroadcastReceiverReceiveIntent(JNIEnv *env, jobject thiz, jobject intent);
View
98 xbmc/android/activity/Intents.cpp
@@ -21,22 +21,84 @@
#include "utils/log.h"
#include "XBMCApp.h"
#include "JNIThreading.h"
+#include <android/native_activity.h>
+
+#include "ApplicationMessenger.h"
+#include "AppParamParser.h"
+#include "URL.h"
+#include "utils/URIUtils.h"
+
+//Intents
+#define ACTION_VIEW "android.intent.action.VIEW"
CAndroidIntents::CAndroidIntents()
{
}
-void CAndroidIntents::ReceiveIntent(JNIEnv *env, const jobject &intent)
+void CAndroidIntents::ReceiveIntent(JNIEnv *, const jobject &intent)
{
- std::string action = GetIntentAction(intent);
+ JNIEnv* env = xbmc_jnienv();
+
+ std::string action = GetIntentAction(env, intent);
CLog::Log(LOGDEBUG,"CAndroidIntents::ReceiveIntent: %s", action.c_str());
}
-std::string CAndroidIntents::GetIntentAction(const jobject &intent)
+void CAndroidIntents::ReceiveInitialIntent(ANativeActivity *activity)
+{
+ JNIEnv* env = xbmc_jnienv();
+
+ jobject oActivity = activity->clazz;
+ jclass cActivity = env->GetObjectClass(oActivity);
+
+ // oIntent = getIntent();
+ jmethodID mgetIntent = env->GetMethodID(cActivity, "getIntent", "()Landroid/content/Intent;");
+ jobject oIntent = env->CallObjectMethod(oActivity, mgetIntent);
+
+ CStdString action = GetIntentAction(env, oIntent);
+ if (action.compare(ACTION_VIEW) == 0)
+ {
+ CStdString data = GetIntentData(env, oIntent);
+ CURL dataUrl(data);
+ if (!URIUtils::ProtocolHasEncodedFilename(dataUrl.GetProtocol()))
+ CURL::Decode(data);
+
+ CXBMCApp::android_printf("CAndroidIntents::ReceiveInitialIntent: %s - %s", action.c_str(), data.c_str());
+
+ int argc = 2;
+ const char** argv = (const char**) malloc(argc*sizeof(char*));
+
+ CStdString exe_name("XBMC");
+ argv[0] = exe_name.c_str();
+ argv[1] = data.c_str();
+
+ CAppParamParser appParamParser;
+ appParamParser.Parse((const char **)argv, argc);
+
+ free(argv);
+ }
+
+ env->DeleteLocalRef(oIntent);
+}
+
+void CAndroidIntents::ReceiveViewIntent(JNIEnv *, const jobject &intent)
{
- std::string action;
JNIEnv* env = xbmc_jnienv();
+ CStdString data = GetIntentData(env, intent);
+ CURL dataUrl(data);
+ if (!URIUtils::ProtocolHasEncodedFilename(dataUrl.GetProtocol()))
+ CURL::Decode(data);
+
+ CXBMCApp::android_printf("CAndroidIntents::ReceiveViewIntent: %s", data.c_str());
+
+ if (data.size() > 0)
+ s_messenger.MediaPlay(data);
+}
+
+std::string CAndroidIntents::GetIntentAction(JNIEnv *env, const jobject &intent)
+{
+ std::string action;
+
if (!intent)
return "";
@@ -46,9 +108,35 @@ std::string CAndroidIntents::GetIntentAction(const jobject &intent)
jmethodID mgetAction = env->GetMethodID(cIntent, "getAction", "()Ljava/lang/String;");
env->DeleteLocalRef(cIntent);
jstring sAction = (jstring)env->CallObjectMethod(intent, mgetAction);
+ if (sAction == NULL)
+ return "";
+
const char *nativeString = env->GetStringUTFChars(sAction, 0);
action = std::string(nativeString);
-
env->ReleaseStringUTFChars(sAction, nativeString);
+
return action;
}
+
+std::string CAndroidIntents::GetIntentData(JNIEnv *env, const jobject &intent)
+{
+ std::string data;
+
+ if (!intent)
+ return "";
+
+ jclass cIntent = env->GetObjectClass(intent);
+
+ //data = intent.getDataString()
+ jmethodID mgetData = env->GetMethodID(cIntent, "getDataString", "()Ljava/lang/String;");
+ env->DeleteLocalRef(cIntent);
+ jstring sData = (jstring)env->CallObjectMethod(intent, mgetData);
+ if (sData == NULL)
+ return "";
+
+ const char *nativeString = env->GetStringUTFChars(sData, 0);
+ data = std::string(nativeString);
+ env->ReleaseStringUTFChars(sData, nativeString);
+
+ return data;
+}
View
10 xbmc/android/activity/Intents.h
@@ -21,15 +21,21 @@
#include <string>
#include <jni.h>
+class ANativeActivity;
+
class CAndroidIntents
{
public:
void ReceiveIntent(JNIEnv *env, const jobject &intent);
+ void ReceiveInitialIntent(ANativeActivity *activity);
+ void ReceiveViewIntent(JNIEnv *env, const jobject &intent);
static CAndroidIntents& getInstance() {static CAndroidIntents temp; return temp;};
-private:
+protected:
CAndroidIntents();
CAndroidIntents(CAndroidIntents const&);
void operator=(CAndroidIntents const&);
- std::string GetIntentAction(const jobject &intent);
+
+ std::string GetIntentAction(JNIEnv *env, const jobject &intent);
+ std::string GetIntentData(JNIEnv *env, const jobject &intent);
};
View
1  xbmc/android/activity/JNIManager.cpp
@@ -77,6 +77,7 @@ bool CAndroidJNIManager::Load(JavaVM* vm, int jniVersion)
return false;
}
+ RegisterClass(env, &g_xbmcapp);
m_broadcastReceiver = new CBroadcastReceiver();
RegisterClass(env, m_broadcastReceiver);
View
17 xbmc/android/activity/XBMCApp.cpp
@@ -27,8 +27,8 @@
#include <android/native_window.h>
#include <android/configuration.h>
-#include <jni.h>
+#include "Intents.h"
#include "XBMCApp.h"
#include "input/MouseStat.h"
@@ -61,7 +61,8 @@ ANativeActivity *CXBMCApp::m_activity = NULL;
ANativeWindow* CXBMCApp::m_window = NULL;
CXBMCApp::CXBMCApp(ANativeActivity *nativeActivity)
- : m_wakeLock(NULL)
+ : CAndroidJNIBase("org/xbmc/xbmc/Main")
+ , m_wakeLock(NULL)
{
m_activity = nativeActivity;
m_firstrun = true;
@@ -72,6 +73,8 @@ CXBMCApp::CXBMCApp(ANativeActivity *nativeActivity)
exit(1);
return;
}
+
+ AddMethod(jniNativeMethod("ReceiveViewIntent", "(Landroid/content/Intent;)V", (void*)jni_MainReceiveViewIntent));
}
CXBMCApp::~CXBMCApp()
@@ -285,6 +288,7 @@ void CXBMCApp::run()
android_printf(" => running XBMC_Run...");
try
{
+ CAndroidIntents::getInstance().ReceiveInitialIntent(m_activity);
status = XBMC_Run(true);
android_printf(" => XBMC_Run finished with %d", status);
}
@@ -975,3 +979,12 @@ void CXBMCApp::SetSystemVolume(JNIEnv *env, float percent)
env->DeleteLocalRef(cAudioManager);
}
+void CXBMCApp::ReceiveViewIntent(JNIEnv *env, jobject thiz, jobject intent)
+{
+ CAndroidIntents::getInstance().ReceiveViewIntent(env, intent);
+}
+
+void jni_MainReceiveViewIntent(JNIEnv *env, jobject thiz, jobject intent)
+{
+ g_xbmcapp.ReceiveViewIntent(env, thiz, intent);
+}
View
9 xbmc/android/activity/XBMCApp.h
@@ -25,6 +25,7 @@
#include <vector>
#include <android/native_activity.h>
+#include "JNIManager.h"
#include "IActivityHandler.h"
#include "IInputHandler.h"
@@ -50,8 +51,12 @@ struct androidPackage
};
-class CXBMCApp : public IActivityHandler
+class CXBMCApp : public IActivityHandler, public CAndroidJNIBase
{
+friend class CAndroidJNIManager;
+public:
+ void ReceiveViewIntent(JNIEnv *env, jobject thiz, jobject intent);
+
public:
CXBMCApp(ANativeActivity *nativeActivity);
virtual ~CXBMCApp();
@@ -125,3 +130,5 @@ class CXBMCApp : public IActivityHandler
bool XBMC_DestroyDisplay();
bool XBMC_SetupDisplay();
};
+
+extern "C" void jni_MainReceiveViewIntent(JNIEnv *env, jobject thiz, jobject intent);
Something went wrong with that request. Please try again.