diff options
Diffstat (limited to 'Android')
24 files changed, 1217 insertions, 0 deletions
diff --git a/Android/.classpath b/Android/.classpath new file mode 100644 index 000000000..a4763d1ee --- /dev/null +++ b/Android/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="gen"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> + <classpathentry kind="output" path="bin/classes"/> +</classpath> diff --git a/Android/.project b/Android/.project new file mode 100644 index 000000000..ad960717b --- /dev/null +++ b/Android/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>MCServer</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.ApkBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>com.android.ide.eclipse.adt.AndroidNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/Android/.settings/org.eclipse.jdt.core.prefs b/Android/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..f77b31c2d --- /dev/null +++ b/Android/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/Android/AndroidManifest.xml b/Android/AndroidManifest.xml new file mode 100644 index 000000000..0a2cc8380 --- /dev/null +++ b/Android/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.mcserver" + android:versionCode="3" + android:versionName="r1375" > + + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.READ_LOGS"/> + + <uses-sdk android:minSdkVersion="10" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" > + <activity + android:name=".MCServerActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest>
\ No newline at end of file diff --git a/Android/assets/basedir/Plugins/README.txt b/Android/assets/basedir/Plugins/README.txt new file mode 100644 index 000000000..1c8259eda --- /dev/null +++ b/Android/assets/basedir/Plugins/README.txt @@ -0,0 +1,2 @@ +Put all pre-packaged plugins in here such as Core. +The user will be able to install each plugin in here separately.
\ No newline at end of file diff --git a/Android/assets/basedir/README.txt b/Android/assets/basedir/README.txt new file mode 100644 index 000000000..784d10fc7 --- /dev/null +++ b/Android/assets/basedir/README.txt @@ -0,0 +1,10 @@ +Put all pre-packaged settings/preferences and license files in here. +Such as: + +settings.example.ini +groups.example.ini +users.example.ini +webadmin.example.ini +Lua-LICENSE.txt +MersenneTwister-LICENSE.txt +etc.etc
\ No newline at end of file diff --git a/Android/assets/basedir/webadmin/README.txt b/Android/assets/basedir/webadmin/README.txt new file mode 100644 index 000000000..96090fd33 --- /dev/null +++ b/Android/assets/basedir/webadmin/README.txt @@ -0,0 +1 @@ +Put pre-packaged webadmin template in here
\ No newline at end of file diff --git a/Android/gen/com/mcserver/BuildConfig.java b/Android/gen/com/mcserver/BuildConfig.java new file mode 100644 index 000000000..e40837927 --- /dev/null +++ b/Android/gen/com/mcserver/BuildConfig.java @@ -0,0 +1,6 @@ +/** Automatically generated file. DO NOT MODIFY */ +package com.mcserver; + +public final class BuildConfig { + public final static boolean DEBUG = true; +}
\ No newline at end of file diff --git a/Android/gen/com/mcserver/R.java b/Android/gen/com/mcserver/R.java new file mode 100644 index 000000000..cbb9e653a --- /dev/null +++ b/Android/gen/com/mcserver/R.java @@ -0,0 +1,39 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package com.mcserver; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int ic_launcher=0x7f020000; + } + public static final class id { + public static final int configure_server=0x7f050003; + public static final int ip_address=0x7f050005; + public static final int listView1=0x7f050006; + public static final int server_status_text=0x7f050004; + public static final int start_server=0x7f050002; + public static final int stop_server=0x7f050001; + public static final int textView2=0x7f050000; + } + public static final class layout { + public static final int list_item=0x7f030000; + public static final int main=0x7f030001; + } + public static final class string { + public static final int app_name=0x7f040001; + public static final int configure=0x7f040007; + public static final int hello=0x7f040000; + public static final int mcserver_is_not_running=0x7f040005; + public static final int mcserver_is_running=0x7f040004; + public static final int start=0x7f040002; + public static final int stop=0x7f040003; + public static final int your_ip=0x7f040006; + } +} diff --git a/Android/jni/Android.mk b/Android/jni/Android.mk new file mode 100644 index 000000000..23488e359 --- /dev/null +++ b/Android/jni/Android.mk @@ -0,0 +1,46 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := mcserver + + + +LOCAL_SRC_FILES := $(shell find ../CryptoPP ../lua-5.1.4 ../jsoncpp-src-0.5.0 ../zlib-1.2.7 ../source ../squirrel_3_0_1_stable ../tolua++-1.0.93 ../iniFile ../WebServer ../expat '(' -name '*.cpp' -o -name '*.c' ')') +LOCAL_SRC_FILES := $(filter-out %SquirrelFunctions.cpp %SquirrelBindings.cpp %cPlugin_Squirrel.cpp %cSquirrelCommandBinder.cpp %minigzip.c %lua.c %tolua.c %toluabind.c %LeakFinder.cpp %StackWalker.cpp %example.c,$(LOCAL_SRC_FILES)) +LOCAL_SRC_FILES := $(patsubst %.cpp,../%.cpp,$(LOCAL_SRC_FILES)) +LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES)) +LOCAL_SRC_FILES += app-android.cpp ToJava.cpp + +LOCAL_CFLAGS := -DANDROID_NDK \ + -O3 \ + -funroll-loops \ + -mfloat-abi=softfp -mfpu=neon \ + -fexceptions \ + + +LOCAL_STATIC_LIBRARIES := cpufeatures + +LOCAL_C_INCLUDES := ../source \ + ../source/md5 \ + ../WebServer \ + ../source/packets \ + ../source/items \ + ../source/blocks \ + ../tolua++-1.0.93/src/lib \ + ../lua-5.1.4/src \ + ../zlib-1.2.7 \ + ../iniFile \ + ../tolua++-1.0.93/include \ + ../jsoncpp-src-0.5.0/include \ + ../jsoncpp-src-0.5.0/src/lib_json \ + ../squirrel_3_0_1_stable/include \ + ../squirrel_3_0_1_stable \ + ../squirrel_3_0_1_stable/sqrat \ + ../expat/ \ + .. \ + + +LOCAL_LDLIBS := -ldl -llog + +include $(BUILD_SHARED_LIBRARY) +$(call import-module,cpufeatures) diff --git a/Android/jni/Application.mk b/Android/jni/Application.mk new file mode 100644 index 000000000..e00c8b5e2 --- /dev/null +++ b/Android/jni/Application.mk @@ -0,0 +1,7 @@ +# Build both ARMv5TE and ARMv7-A machine code. +APP_MODULES := mcserver +# APP_ABI := armeabi armeabi-v7a +#APP_STL := stlport_static + +APP_STL := gnustl_static +APP_CPPFLAGS := -frtti
\ No newline at end of file diff --git a/Android/jni/ToJava.cpp b/Android/jni/ToJava.cpp new file mode 100644 index 000000000..8db22dd1d --- /dev/null +++ b/Android/jni/ToJava.cpp @@ -0,0 +1,3 @@ +#include "Globals.h" + +#include "ToJava.h"
\ No newline at end of file diff --git a/Android/jni/ToJava.h b/Android/jni/ToJava.h new file mode 100644 index 000000000..11979c847 --- /dev/null +++ b/Android/jni/ToJava.h @@ -0,0 +1,59 @@ +#pragma once + +#include <jni.h> +#include <android/log.h> +extern JNIEnv* g_CurrentJNIEnv; +extern JavaVM* g_JavaVM; +extern jobject g_JavaThread; +//extern jobject g_JavaActivity; + +//__android_log_vprint(ANDROID_LOG_ERROR,"MCServer", a_Format, argList); + +static void CallJavaFunction_Void_String( jobject a_Object, const std::string & a_FunctionName, const std::string & a_StringParam ) +{ + JNIEnv * oldEnv = g_CurrentJNIEnv; + int status = g_JavaVM->AttachCurrentThread(&g_CurrentJNIEnv, NULL); + __android_log_print(ANDROID_LOG_ERROR,"MCServer", "STATUS: %i old: %p new: %p", status, oldEnv, g_CurrentJNIEnv ); + jstring str = g_CurrentJNIEnv->NewStringUTF( a_StringParam.c_str() ); + + + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "JNIEnv: %i Object: %i", g_CurrentJNIEnv, a_Object ); + jclass cls = g_CurrentJNIEnv->GetObjectClass( a_Object ); + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "jclass: %i", cls ); + jmethodID mid = g_CurrentJNIEnv->GetMethodID( cls, a_FunctionName.c_str(), "(Ljava/lang/String;)V"); // void a_FunctionName( String ) + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "jmethodID: %i", mid ); + if (mid != 0) + { + + __android_log_print(ANDROID_LOG_ERROR,"MCServer", "Going to call right NOW! %s", a_FunctionName.c_str() ); + g_CurrentJNIEnv->CallVoidMethod( a_Object, mid, str ); + } + else + { + __android_log_print(ANDROID_LOG_ERROR,"MCServer", "It was 0, derp" ); + } + + if( oldEnv != g_CurrentJNIEnv ) + { + g_JavaVM->DetachCurrentThread(); + } +} + + +static void CallJavaFunction_Void_Void( jobject a_Object, const std::string & a_FunctionName ) +{ + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "JNIEnv: %i Object: %i", g_CurrentJNIEnv, a_Object ); + jclass cls = g_CurrentJNIEnv->GetObjectClass( a_Object ); + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "jclass: %i", cls ); + jmethodID mid = g_CurrentJNIEnv->GetMethodID( cls, a_FunctionName.c_str(), "()V"); // void a_FunctionName( String ) + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "jmethodID: %i", mid ); + if (mid != 0) + { + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "Going to call right NOW! %s", a_FunctionName.c_str() ); + g_CurrentJNIEnv->CallVoidMethod( a_Object, mid ); + } + else + { + __android_log_print(ANDROID_LOG_ERROR,"MCServer", "It was 0, derp" ); + } +}
\ No newline at end of file diff --git a/Android/jni/app-android.cpp b/Android/jni/app-android.cpp new file mode 100644 index 000000000..197df29c4 --- /dev/null +++ b/Android/jni/app-android.cpp @@ -0,0 +1,130 @@ +#include "Globals.h" + +#include <jni.h> +#include <sys/time.h> +#include <time.h> +#include <stdint.h> + +#include <stdlib.h> +#include <math.h> +#include <float.h> +#include <assert.h> + +#include "OSSupport/CriticalSection.h" +#include "OSSupport/MakeDir.h" +#include "ToJava.h" + +#include "Root.h" +#include "WebAdmin.h" + +#include <android/log.h> + +#ifdef _WIN32 // For IntelliSense parsing +typedef void jobject; +typedef int jint; +typedef bool jboolean; +typedef void JavaVM; +typedef void JNIEnv; +#endif + +cCriticalSection g_CriticalSection; + +JNIEnv* g_CurrentJNIEnv = 0; +jobject g_JavaThread = 0; +JavaVM* g_JavaVM = 0; +//jobject g_JavaActivity = 0; + +cRoot * pRoot = NULL; + + +class cMainThread : + public cIsThread +{ +public: + cMainThread() : + cIsThread("cMainThread") + { + //Start(); + __android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "cMainThread"); + } + + void Stop(void) + { + m_ShouldTerminate = true; + Wait(); + } + +protected: + + virtual void Execute(void) override + { + __android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "Execute"); + pRoot = new cRoot(); + pRoot->Start(); + delete pRoot; + } + +} ; + +cMainThread * pMainThread = NULL; + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "JNI_OnLoad JNI_OnLoad JNI_OnLoad JNI_OnLoad"); + g_JavaVM = vm; + return JNI_VERSION_1_4; +} + +/* Called when program/activity is created */ +extern "C" void Java_com_mcserver_MCServerActivity_NativeOnCreate( JNIEnv* env, jobject thiz ) +{ + g_CriticalSection.Lock(); + g_CurrentJNIEnv = env; + g_JavaThread = thiz; + //__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "Logging from C++!"); + g_CriticalSection.Unlock(); + + mkdir("/sdcard/mcserver", S_IRWXU | S_IRWXG | S_IRWXO); + + pRoot = new cRoot(); + pRoot->Start(); + delete pRoot; pRoot = NULL; +} + + + + + +extern "C" void Java_com_mcserver_MCServerActivity_NativeCleanUp( JNIEnv* env, jobject thiz ) +{ + g_CriticalSection.Lock(); + g_CurrentJNIEnv = env; + g_JavaThread = thiz; + g_CriticalSection.Unlock(); + + __android_log_print(ANDROID_LOG_ERROR,"MCServer", "pRoot: %p", pRoot); + if( pRoot != NULL ) + { + pRoot->ExecuteConsoleCommand("stop"); + } +} + + + + +extern "C" jboolean Java_com_mcserver_MCServerActivity_NativeIsServerRunning( JNIEnv* env, jobject thiz ) +{ + return pRoot != NULL; +} + + + + +extern "C" jint Java_com_mcserver_MCServerActivity_NativeGetWebAdminPort( JNIEnv* env, jobject thiz ) +{ + if( pRoot != NULL && pRoot->GetWebAdmin() != NULL ) + { + return pRoot->GetWebAdmin()->GetPort(); + } + return 0; +}
\ No newline at end of file diff --git a/Android/proguard-project.txt b/Android/proguard-project.txt new file mode 100644 index 000000000..f2fe1559a --- /dev/null +++ b/Android/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/Android/project.properties b/Android/project.properties new file mode 100644 index 000000000..7a6518b77 --- /dev/null +++ b/Android/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt + +# Project target. +target=android-12 diff --git a/Android/res/drawable-hdpi/ic_launcher.png b/Android/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..d8a74a2d8 --- /dev/null +++ b/Android/res/drawable-hdpi/ic_launcher.png diff --git a/Android/res/drawable-ldpi/ic_launcher.png b/Android/res/drawable-ldpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..5fa7251f8 --- /dev/null +++ b/Android/res/drawable-ldpi/ic_launcher.png diff --git a/Android/res/drawable-mdpi/ic_launcher.png b/Android/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..0e3af7c05 --- /dev/null +++ b/Android/res/drawable-mdpi/ic_launcher.png diff --git a/Android/res/drawable-xhdpi/ic_launcher.png b/Android/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..60b19df2d --- /dev/null +++ b/Android/res/drawable-xhdpi/ic_launcher.png diff --git a/Android/res/layout/main.xml b/Android/res/layout/main.xml new file mode 100644 index 000000000..4ff238d80 --- /dev/null +++ b/Android/res/layout/main.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="center_horizontal" + android:orientation="vertical" > + + <TextView + android:id="@+id/textView2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/app_name" + android:textAppearance="?android:attr/textAppearanceLarge" /> +
+ <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" > +
+ <Button + android:id="@+id/stop_server" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:enabled="true" + android:text="@string/stop" /> +
+ <Button + android:id="@+id/start_server" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/start" /> +
+ <Button + android:id="@+id/configure_server" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/configure" /> + + </LinearLayout> + + <TextView + android:id="@+id/server_status_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/mcserver_is_not_running" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <TextView + android:id="@+id/ip_address" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/your_ip" /> + <ListView + android:id="@+id/listView1" + android:layout_width="match_parent" + android:layout_height="wrap_content" > + </ListView> + +</LinearLayout>
\ No newline at end of file diff --git a/Android/res/values/strings.xml b/Android/res/values/strings.xml new file mode 100644 index 000000000..9eb81d653 --- /dev/null +++ b/Android/res/values/strings.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="hello">Hello World, MCServerActivity!</string> + <string name="app_name">MCServer</string> + <string name="start">Start</string> + <string name="stop">Stop</string> + <string name="mcserver_is_running">MCServer is running</string> + <string name="mcserver_is_not_running">MCServer is not running</string> + <string name="your_ip">Your IP …</string> + <string name="configure">Configure</string> + +</resources>
\ No newline at end of file diff --git a/Android/src/com/mcserver/MCServerActivity.java b/Android/src/com/mcserver/MCServerActivity.java new file mode 100644 index 000000000..8a9846ca1 --- /dev/null +++ b/Android/src/com/mcserver/MCServerActivity.java @@ -0,0 +1,302 @@ +package com.mcserver; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Enumeration; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ListView; +import android.widget.TextView; + +public class MCServerActivity extends Activity { + MainThread mThread = null; + Thread ServerStatusThread = null; + boolean mbExiting = false; + boolean mbEnabledLogging = false; + + ArrayList<String> mLogList = new ArrayList<String>(); + ArrayAdapter<String> mAdapter; + + MCServerInstaller mInstaller = null; + + final private int MENU_REINSTALL = 0; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + //Log.e("MCServer", "p id: " + android.os.Process.myPid() ); + + + ((Button)findViewById(R.id.start_server)).setOnClickListener( new View.OnClickListener() { + public void onClick(View v) { + mbEnabledLogging = true; + if( mThread == null || mThread.isAlive() == false ) { + mThread = new MainThread( (MCServerActivity)v.getContext() ); + mThread.start(); + } + } + }); + + ((Button)findViewById(R.id.stop_server)).setOnClickListener( new View.OnClickListener() { + public void onClick(View v) { + mbEnabledLogging = true; + NativeCleanUp(); + } + }); + + ((Button)findViewById(R.id.configure_server)).setOnClickListener( new View.OnClickListener() { + public void onClick(View v) { + Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://localhost:" + NativeGetWebAdminPort() + "/webadmin/")); + startActivity( myIntent ); + } + }); + + + + ListView lv = (ListView)this.findViewById(R.id.listView1); + mAdapter = new ArrayAdapter<String>(this, + R.layout.list_item, + mLogList); + lv.setAdapter(mAdapter); + + + mLogList.add("---- LOG ----"); + + ServerStatusThread = new Thread( new Runnable() { + public void run() { + for(;;) + { + try { + runOnUiThread( new Runnable() { + public void run() { + UpdateServerStatus(); + } + }); + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + } + }); + ServerStatusThread.start(); + + + + + + + + Thread loggerThread = new Thread( new Runnable() { + public void run() { + Process process = null; + + try { + process = Runtime.getRuntime().exec("logcat -v raw *:s MCServer ");// Verbose filter + } catch (IOException e) { + } + + BufferedReader reader = null; + + try { + InputStreamReader isr = new InputStreamReader(process.getInputStream()); + reader = new BufferedReader( isr ); + + String line; + + while( mbExiting == false ) { + line = reader.readLine(); + if( mbEnabledLogging == true && line != null ) + { + AddToLog( line ); + } + } + + Log.i("MCServer", "Prepping thread for termination"); + reader.close(); + process.destroy(); + process = null; + reader = null; + } catch (IOException e) { + } + } + }); + loggerThread.start(); + + ((TextView)findViewById(R.id.ip_address)).setText("Connect to: " + getLocalIpAddress()); + + + mInstaller = new MCServerInstaller(this); + if( mInstaller.NeedsUpdate() ) + { + mInstaller.ShowFirstRunDialog(); + } + } + + + + public String getLocalIpAddress() { + try { + for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { + NetworkInterface intf = en.nextElement(); + for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { + InetAddress inetAddress = enumIpAddr.nextElement(); + if (!inetAddress.isLoopbackAddress()) { + return inetAddress.getHostAddress().toString(); + } + } + } + } catch (SocketException ex) { + Log.e("MCServer", ex.toString()); + } + return null; + } + + + + public void UpdateServerStatus() + { + if( NativeIsServerRunning() ) { + ((TextView)findViewById(R.id.server_status_text)).setText(R.string.mcserver_is_running); + ((TextView)findViewById(R.id.server_status_text)).setTextColor(Color.GREEN); + ((Button)findViewById(R.id.stop_server)).setEnabled(true); + ((Button)findViewById(R.id.start_server)).setEnabled(false); + ((Button)findViewById(R.id.configure_server)).setEnabled(true); + } else { + ((TextView)findViewById(R.id.server_status_text)).setText(R.string.mcserver_is_not_running); + ((TextView)findViewById(R.id.server_status_text)).setTextColor(Color.RED); + ((Button)findViewById(R.id.stop_server)).setEnabled(false); + ((Button)findViewById(R.id.start_server)).setEnabled(true); + ((Button)findViewById(R.id.configure_server)).setEnabled(false); + } + } + + + + + + public boolean onKeyDown(int keyCode, KeyEvent event) { + if(keyCode==KeyEvent.KEYCODE_BACK) + { + //android.os.Process.killProcess(android.os.Process.myPid()); + NativeCleanUp(); + return super.onKeyDown(keyCode, event); + } + return false; + } + + + + + public void onDestroy() { + mbExiting = true; + super.onDestroy(); + } + + + + + + public void AddToLog( final String logMessage ) { + final ListView lv = ((ListView)findViewById(R.id.listView1)); + lv.post(new Runnable() { + public void run() { + //final boolean bAutoscroll = lv.getLastVisiblePosition() >= mAdapter.getCount() - 1 ? true : false; + + mLogList.add(logMessage); + while( mLogList.size() > 100 ) // only allow 100 messages in the list, otherwise it might slow the GUI down + { + mLogList.remove(0); + } + mAdapter.notifyDataSetChanged(); + + + // Autoscroll detection is dodgy + //if( bAutoscroll ) + { + lv.setSelection(mAdapter.getCount() - 1); + } + } + }); + } + + + + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, MENU_REINSTALL, 0, "Reinstall MCServer" ); + return super.onCreateOptionsMenu(menu); + } + + + + + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + switch( item.getItemId() ) + { + case MENU_REINSTALL: + mInstaller.ShowPluginInstallDialog(true); + return true; + } + return false; + } + + + + + + static { + System.loadLibrary("mcserver"); + } + + + public native void NativeOnCreate(); + public native void NativeCleanUp(); + public native boolean NativeIsServerRunning(); + public native int NativeGetWebAdminPort(); + +} + + +class MainThread extends Thread { + MCServerActivity mContext = null; + int numlogs = 0; + + MainThread( MCServerActivity aContext ) { + mContext = aContext; + } + + public void run() { + mContext.NativeOnCreate(); + } + +} + + + + + + diff --git a/Android/src/com/mcserver/MCServerInstaller.java b/Android/src/com/mcserver/MCServerInstaller.java new file mode 100644 index 000000000..5a865a602 --- /dev/null +++ b/Android/src/com/mcserver/MCServerInstaller.java @@ -0,0 +1,432 @@ +package com.mcserver; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.AssetManager; +import android.os.AsyncTask; +import android.os.Environment; +import android.util.Log; + +public class MCServerInstaller { + private MCServerActivity mContext; + final private String BaseDirectory = "basedir"; + final private String PluginDirectory = "Plugins"; + + final public String SHARED_PREFS_NAME = "MCSERVER_PREFS"; + final public String PREF_IS_INSTALLED = "IS_INSTALLED"; + final public String PREF_LAST_VERSION = "LAST_VERSION"; + private SharedPreferences mSettings = null; + + int thisVersion; + + MCServerInstaller( MCServerActivity activity ) + { + mContext = activity; + + mSettings = mContext.getSharedPreferences( SHARED_PREFS_NAME, 0); + + try { + this.thisVersion = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionCode; + } catch (NameNotFoundException e) { + Log.e("MCServer", "Could not read version code from manifest!"); + e.printStackTrace(); + this.thisVersion = -1; + } + } + + + public boolean IsInstalled() + { + return mSettings.getBoolean(PREF_IS_INSTALLED, false); + } + + + public boolean NeedsUpdate() + { + Log.i("MCServer", "thisVersion: " + this.thisVersion + " pref: " + mSettings.getInt(PREF_LAST_VERSION, 0)); + return mSettings.getInt(PREF_LAST_VERSION, 0) != this.thisVersion; + } + + + public ArrayList<String> FindFoldersInPath(String path) + { + ArrayList<String> allFolders = new ArrayList<String>(); + AssetManager am = mContext.getAssets(); + try { + String[] allPlugins = am.list(path); + for(String pluginName : allPlugins) + { + InputStream istr = null; + try + { + istr = am.open(path + "/" + pluginName); + } catch( java.io.FileNotFoundException e ) { + // It seems to be a folder :D + allFolders.add(pluginName); + continue; + } + istr.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + return allFolders; + } + + + + + public void ExpandAssets( String path ) + { + AssetManager am = mContext.getAssets(); + try { + String[] getAssets = am.list(path); + for(String assetName : getAssets) + { + //Log.e("MCServer", path + "/" + imgName); + + InputStream istr = null; + try + { + istr = am.open(path + "/" + assetName); + } catch( java.io.FileNotFoundException e ) { + //Log.e("MCServer", "Could not open" + path + "/" + imgName ); + ExpandAssets(path + "/" + assetName); + continue; + } + + String outPath = Environment.getExternalStorageDirectory().getPath() + "/mcserver/" + path + "/" + assetName; + //Log.e("MCServer", "outPath: " + outPath ); + File f = new File( outPath ); + + f.getParentFile().mkdirs(); + f.createNewFile(); + OutputStream ostr = new FileOutputStream(f); + + byte[] buffer = new byte[1024]; + int length; + while ((length = istr.read(buffer))>0) + { + ostr.write(buffer, 0, length); + } + ostr.flush(); + ostr.close(); + istr.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + + void ShowFirstRunDialog() + { + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + //builder.setTitle("blaa"); + builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + builder.setMessage("It seems this is the first time you are running MCServer on your Android device or it has been updated! This app comes with a couple of pre-packaged plugins, please take a moment to select the plugins you would like to install."); + builder.setCancelable(false); + AlertDialog dialog = builder.create(); + dialog.show(); + + dialog.setOnDismissListener( new DialogInterface.OnDismissListener(){ + public void onDismiss(DialogInterface dialog) { + ShowPluginInstallDialog(false); + } + }); + } + + + public void ShowPluginInstallDialog(boolean bCancelable) + { + final ArrayList<String> allPlugins = FindFoldersInPath( BaseDirectory + "/" + PluginDirectory ); + final CharSequence[] items = allPlugins.toArray(new CharSequence[allPlugins.size()]); + final boolean[] selected = new boolean[items.length]; + for( int i = 0; i < items.length; ++i ) + { + if( items[i].toString().contains("Core") ) + { // Select the core plugin by default + selected[i] = true; + items[i] = items[i] + " (Recommended)"; + } + } + + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + builder.setTitle("Plugins to install"); + builder.setCancelable(bCancelable); + builder.setMultiChoiceItems(items, selected, new DialogInterface.OnMultiChoiceClickListener() { + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + selected[which] = isChecked; + } + }); + builder.setPositiveButton("Install", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + ArrayList<String> toInstall = new ArrayList<String>(); + for( int i = 0; i < selected.length; ++i ) + { + if( selected[i] ) + { + toInstall.add(allPlugins.get(i)); + } + } + InstallPlugins(toInstall); + } + }); + + AlertDialog dialog2 = builder.create(); + dialog2.show(); + } + + + void InstallPlugins( final ArrayList<String> plugins ) + { + new AsyncTask<Void, Integer, Boolean>() + { + ProgressDialog progressDialog; + + @Override + protected void onPreExecute() + { + /* + * This is executed on UI thread before doInBackground(). It is + * the perfect place to show the progress dialog. + */ + progressDialog = ProgressDialog.show(mContext, "", "Installing..."); + + } + + @Override + protected Boolean doInBackground(Void... params) + { + if (params == null) + { + return false; + } + try + { + /* + * This is run on a background thread, so we can sleep here + * or do whatever we want without blocking UI thread. A more + * advanced use would download chunks of fixed size and call + * publishProgress(); + */ + for( int i = 0; i < plugins.size(); ++i ) + { + this.publishProgress((int)(i / (float)plugins.size() * 100), i); + InstallSinglePlugin(PluginDirectory + "/" + plugins.get(i)); + } + + this.publishProgress( 100, -1 ); + InstallExampleSettings(); + + this.publishProgress( 100, -2 ); + InstallWebAdmin(); + + } + catch (Exception e) + { + Log.e("tag", e.getMessage()); + /* + * The task failed + */ + return false; + } + + /* + * The task succeeded + */ + return true; + } + + protected void onProgressUpdate(Integer... progress) + { + progressDialog.setProgress(progress[0]); + if( progress[1] > -1 ) + { + progressDialog.setMessage("Installing " + plugins.get(progress[1]) + "..." ); + } + else if( progress[1] == -1 ) + { + progressDialog.setMessage("Installing default settings..."); + } + else if( progress[1] == -2 ) + { + progressDialog.setMessage("Installing WebAdmin..."); + } + } + + @Override + protected void onPostExecute(Boolean result) + { + progressDialog.dismiss(); + /* + * Update here your view objects with content from download. It + * is save to dismiss dialogs, update views, etc., since we are + * working on UI thread. + */ + AlertDialog.Builder b = new AlertDialog.Builder(mContext); + b.setTitle(android.R.string.dialog_alert_title); + if (result) + { + b.setMessage("Install succeeded"); + + SharedPreferences.Editor editor = mSettings.edit(); + editor.putBoolean(PREF_IS_INSTALLED, true); + editor.putInt(PREF_LAST_VERSION, thisVersion); + editor.commit(); + } + else + { + b.setMessage("Install failed"); + } + b.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() + { + public void onClick(DialogInterface dialog, int which) + { + dialog.dismiss(); + } + }); + b.create().show(); + } + }.execute(); + } + + + void InstallExampleSettings() + { + AssetManager am = mContext.getAssets(); + try { + String[] allFiles = am.list(BaseDirectory); + for(String fileName : allFiles) + { + InputStream istr = null; + try + { + istr = am.open(BaseDirectory + "/" + fileName); + } catch( java.io.FileNotFoundException e ) { + // Must be a folder :D + continue; + } + + String outPath = Environment.getExternalStorageDirectory().getPath() + "/mcserver/" + fileName; + Log.i("MCServer", "outPath: " + outPath ); + File f = new File( outPath ); + + f.getParentFile().mkdirs(); + f.createNewFile(); + OutputStream ostr = new FileOutputStream(f); + + byte[] buffer = new byte[1024]; + int length; + while ((length = istr.read(buffer))>0) + { + ostr.write(buffer, 0, length); + } + ostr.flush(); + ostr.close(); + istr.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + + void InstallWebAdmin() + { + AssetManager am = mContext.getAssets(); + try { + String[] allFiles = am.list(BaseDirectory + "/webadmin"); + for(String fileName : allFiles) + { + InputStream istr = null; + try + { + istr = am.open(BaseDirectory + "/webadmin/" + fileName); + } catch( java.io.FileNotFoundException e ) { + // Must be a folder :D + continue; + } + + String outPath = Environment.getExternalStorageDirectory().getPath() + "/mcserver/webadmin/" + fileName; + Log.i("MCServer", "outPath: " + outPath ); + File f = new File( outPath ); + + f.getParentFile().mkdirs(); + f.createNewFile(); + OutputStream ostr = new FileOutputStream(f); + + byte[] buffer = new byte[1024]; + int length; + while ((length = istr.read(buffer))>0) + { + ostr.write(buffer, 0, length); + } + ostr.flush(); + ostr.close(); + istr.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + + void InstallSinglePlugin( String path ) + { + AssetManager am = mContext.getAssets(); + try { + String[] getImages = am.list(BaseDirectory + "/" + path); + for(String imgName : getImages) + { + Log.i("MCServer", path + "/" + imgName); + + InputStream istr = null; + try + { + istr = am.open(BaseDirectory + "/" + path + "/" + imgName); + } catch( java.io.FileNotFoundException e ) { + Log.i("MCServer", "Could not open" + path + "/" + imgName ); + InstallSinglePlugin(path + "/" + imgName); + continue; + } + + String outPath = Environment.getExternalStorageDirectory().getPath() + "/mcserver/" + path + "/" + imgName; + Log.i("MCServer", "outPath: " + outPath ); + File f = new File( outPath ); + + f.getParentFile().mkdirs(); + f.createNewFile(); + OutputStream ostr = new FileOutputStream(f); + + byte[] buffer = new byte[1024]; + int length; + while ((length = istr.read(buffer))>0) + { + ostr.write(buffer, 0, length); + } + ostr.flush(); + ostr.close(); + istr.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} |