mirror of
https://github.com/edubart/otclient.git
synced 2025-11-03 04:06:23 +01:00
Removed SDL2 and created JNI interface (Android Only)
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.libsdl.app" android:versionCode="1" android:versionName="1.0">
|
||||
|
||||
<uses-sdk android:minSdkVersion="16"/>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.otclient.mobile" android:versionCode="1" android:versionName="1.0">
|
||||
|
||||
<application
|
||||
android:debuggable="true"
|
||||
android:debuggable="true"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:hardwareAccelerated="true" >
|
||||
|
||||
<activity android:name="SDLActivity"
|
||||
<activity android:name="MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
android:configChanges="orientation|keyboardHidden">
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:screenOrientation="landscape">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
@@ -24,7 +23,7 @@
|
||||
</application>
|
||||
|
||||
<!-- Android 2.3.3 -->
|
||||
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="12"/>
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="16"/>
|
||||
|
||||
<!-- OpenGL ES 2.0 -->
|
||||
<uses-feature android:glEsVersion="0x00020000"/>
|
||||
|
||||
@@ -3,9 +3,4 @@ LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libotclient
|
||||
LOCAL_SRC_FILES := libotclient.so
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libSDL2
|
||||
LOCAL_SRC_FILES := libSDL2.so
|
||||
include $(PREBUILT_SHARED_LIBRARY)
|
||||
@@ -1,2 +1,2 @@
|
||||
APP_PLATFORM := android-16
|
||||
APP_PLATFORM := android-9
|
||||
APP_ABI := armeabi-v7a
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">OTClientMob</string>
|
||||
<string name="app_name">OTClient</string>
|
||||
</resources>
|
||||
|
||||
52
android/project/src/com/otclient/mobile/FakeEditText.java
Normal file
52
android/project/src/com/otclient/mobile/FakeEditText.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package com.otclient.mobile;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
public class FakeEditText extends View implements View.OnKeyListener {
|
||||
InputConnection ic;
|
||||
|
||||
public FakeEditText() {
|
||||
super(MainActivity.getInstance());
|
||||
setFocusableInTouchMode(true);
|
||||
setFocusable(true);
|
||||
setOnKeyListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCheckIsTextEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override // This handles the hardware keyboard input
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (event.isPrintingKey()) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
onNativeKeyDown(keyCode);
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
onNativeKeyUp(keyCode);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
ic = new InputConnectionForNative(this, true);
|
||||
|
||||
return ic;
|
||||
}
|
||||
|
||||
public static native void onNativeKeyDown(int keyCode);
|
||||
public static native void onNativeKeyUp(int keyCode);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.otclient.mobile;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
|
||||
public class InputConnectionForNative extends BaseInputConnection {
|
||||
|
||||
public InputConnectionForNative(View targetView, boolean fullEditor) {
|
||||
super(targetView, fullEditor);
|
||||
}
|
||||
|
||||
@Override // This handles the keycodes from soft keyboard
|
||||
public boolean sendKeyEvent(KeyEvent event) {
|
||||
int keyCode = event.getKeyCode();
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (event.isPrintingKey()) {
|
||||
commitText(String.valueOf((char) event.getUnicodeChar()), 1);
|
||||
}
|
||||
FakeEditText.onNativeKeyDown(keyCode);
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
FakeEditText.onNativeKeyUp(keyCode);
|
||||
return true;
|
||||
}
|
||||
return super.sendKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override // Typed text
|
||||
public boolean commitText(CharSequence text, int newCursorPosition) {
|
||||
nativeCommitText(text.toString(), newCursorPosition);
|
||||
|
||||
return super.commitText(text, newCursorPosition);
|
||||
}
|
||||
|
||||
@Override // Workaround to capture backspace key
|
||||
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
||||
if (beforeLength == 1 && afterLength == 0) {
|
||||
return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
|
||||
&& super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
|
||||
}
|
||||
|
||||
return super.deleteSurroundingText(beforeLength, afterLength);
|
||||
}
|
||||
|
||||
public static native void nativeCommitText(String text, int newCursorPosition);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.otclient.mobile;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
public class KeyboardSoftHandler{
|
||||
private View editText;
|
||||
|
||||
public KeyboardSoftHandler() {
|
||||
editText = new FakeEditText();
|
||||
MainActivity.getInstance()
|
||||
.addViewToLayout(editText);
|
||||
}
|
||||
|
||||
public void showKeyboardSoft() {
|
||||
editText.setVisibility(View.VISIBLE);
|
||||
editText.requestFocus();
|
||||
|
||||
InputMethodManager imm = (InputMethodManager) MainActivity
|
||||
.getInstance().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(editText, 0);
|
||||
}
|
||||
|
||||
public void hideKeyboardSoft() {
|
||||
editText.setVisibility(View.GONE);
|
||||
|
||||
InputMethodManager imm = (InputMethodManager) MainActivity
|
||||
.getInstance().getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
110
android/project/src/com/otclient/mobile/MainActivity.java
Normal file
110
android/project/src/com/otclient/mobile/MainActivity.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package com.otclient.mobile;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.RelativeLayout.LayoutParams;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
public static final String APP_TAG = "OTClientMob";
|
||||
|
||||
private static MainActivity instance;
|
||||
private RelativeLayout layout;
|
||||
|
||||
private static boolean started;
|
||||
|
||||
static {
|
||||
started = false;
|
||||
//android.os.Debug.waitForDebugger();
|
||||
System.loadLibrary("otclient");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
Log.v(APP_TAG, "onCreate()");
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
instance = this;
|
||||
|
||||
layout = new RelativeLayout(this);
|
||||
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
|
||||
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
layout.setLayoutParams(params);
|
||||
|
||||
setContentView(layout);
|
||||
|
||||
if( !started ) {
|
||||
nativeInit();
|
||||
started = true;
|
||||
}
|
||||
|
||||
NativeFacadeCalls.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.v(APP_TAG, "onPause()");
|
||||
super.onPause();
|
||||
nativePause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log.v(APP_TAG, "onResume()");
|
||||
super.onResume();
|
||||
|
||||
if( NativeFacadeCalls.isSurfaceReady() )
|
||||
nativeResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
Log.v(APP_TAG, "onDestroy()");
|
||||
super.onDestroy();
|
||||
|
||||
if(isFinishing()) {
|
||||
NativeFacadeCalls.destroy();
|
||||
destroy();
|
||||
nativeDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
private void destroy() {
|
||||
instance = null;
|
||||
layout = null;
|
||||
}
|
||||
|
||||
@Override // Ignore certain special keys so they're handled by Android
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
int keyCode = event.getKeyCode();
|
||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
|
||||
keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
|
||||
keyCode == KeyEvent.KEYCODE_CAMERA ||
|
||||
keyCode == 168 || /* API 11: KeyEvent.KEYCODE_ZOOM_IN */
|
||||
keyCode == 169 /* API 11: KeyEvent.KEYCODE_ZOOM_OUT */
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
public static MainActivity getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void addViewToLayout(View view) {
|
||||
layout.addView(view);
|
||||
}
|
||||
|
||||
public native void nativeInit();
|
||||
public native void nativePause();
|
||||
public native void nativeResume();
|
||||
public native void nativeDestroy();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.otclient.mobile;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.Surface;
|
||||
|
||||
public class NativeFacadeCalls {
|
||||
private static NativeSurfaceView nativeSurfaceView;
|
||||
private static KeyboardSoftHandler keyboardSoftHandler;
|
||||
private static Handler handler;
|
||||
|
||||
public static void initialize() {
|
||||
handler = new Handler(Looper.getMainLooper());
|
||||
keyboardSoftHandler = new KeyboardSoftHandler();
|
||||
nativeSurfaceView = new NativeSurfaceView();
|
||||
MainActivity.getInstance().addViewToLayout(nativeSurfaceView);
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
handler = null;
|
||||
nativeSurfaceView = null;
|
||||
keyboardSoftHandler = null;
|
||||
}
|
||||
|
||||
public static boolean isSurfaceReady() {
|
||||
return nativeSurfaceView.isSurfaceReady();
|
||||
}
|
||||
|
||||
/*
|
||||
* Static methods called from JNI
|
||||
*/
|
||||
|
||||
public static Surface getNativeSurface() {
|
||||
return nativeSurfaceView.getSurface();
|
||||
}
|
||||
|
||||
public static void showKeyboardSoft() {
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
keyboardSoftHandler.showKeyboardSoft();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.otclient.mobile;
|
||||
|
||||
public class NativeMainThread {
|
||||
private static final NativeMainThread instance;
|
||||
private Thread nativeThread;
|
||||
|
||||
static {
|
||||
instance = new NativeMainThread();
|
||||
}
|
||||
|
||||
private NativeMainThread() {}
|
||||
|
||||
public void start() {
|
||||
if( nativeThread == null ) {
|
||||
nativeThread = new Thread(
|
||||
new NativeThread(), "NativeThread" );
|
||||
nativeThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static NativeMainThread getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/*
|
||||
* Native methods implemented on C++
|
||||
*/
|
||||
|
||||
public native void nativeStartApp();
|
||||
|
||||
private class NativeThread implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
nativeStartApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
130
android/project/src/com/otclient/mobile/NativeSurfaceView.java
Normal file
130
android/project/src/com/otclient/mobile/NativeSurfaceView.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package com.otclient.mobile;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
|
||||
public class NativeSurfaceView extends SurfaceView implements
|
||||
SurfaceHolder.Callback, View.OnTouchListener {
|
||||
|
||||
private Surface surface;
|
||||
private GestureDetector gestureDetector;
|
||||
private int currentWidth;
|
||||
private int currentHeight;
|
||||
private boolean surfaceReady;
|
||||
|
||||
private final int LONGPRESS_EVENT = 3;
|
||||
|
||||
public NativeSurfaceView() {
|
||||
super(MainActivity.getInstance());
|
||||
getHolder().addCallback(this);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
requestFocus();
|
||||
setOnTouchListener(this);
|
||||
|
||||
currentWidth = 0;
|
||||
currentHeight = 0;
|
||||
surfaceReady = false;
|
||||
|
||||
gestureDetector = new GestureDetector(
|
||||
new GestureDetector.SimpleOnGestureListener() {
|
||||
public void onLongPress(MotionEvent event) {
|
||||
onNativeTouch(LONGPRESS_EVENT, event.getX(), event.getY());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
Log.d(MainActivity.APP_TAG, "surfaceCreated");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width,
|
||||
int height) {
|
||||
Log.d(MainActivity.APP_TAG, "surfaceChanged");
|
||||
|
||||
surface = holder.getSurface();
|
||||
|
||||
currentWidth = width;
|
||||
currentHeight = height;
|
||||
surfaceReady = true;
|
||||
|
||||
onNativeResize(width, height);
|
||||
onNativeSurfaceChanged();
|
||||
|
||||
NativeMainThread.getInstance().start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
Log.d(MainActivity.APP_TAG, "surfaceDestroyed");
|
||||
surface = null;
|
||||
surfaceReady = false;
|
||||
|
||||
onNativeSurfaceDestroyed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
gestureDetector.onTouchEvent(event);
|
||||
/* Ref: http://developer.android.com/training/gestures/multi.html */
|
||||
final int pointerCount = event.getPointerCount();
|
||||
int action = event.getActionMasked();
|
||||
int i = -1;
|
||||
float x,y;
|
||||
|
||||
switch(action) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
for (i = 0; i < pointerCount; i++) {
|
||||
x = event.getX(i);
|
||||
y = event.getY(i);
|
||||
onNativeTouch(action, x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// Primary pointer up/down, the index is always zero
|
||||
i = 0;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// Non primary pointer up/down
|
||||
if (i == -1) {
|
||||
i = event.getActionIndex();
|
||||
}
|
||||
|
||||
x = event.getX(i);
|
||||
y = event.getY(i);
|
||||
onNativeTouch(action, x, y);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Surface getSurface() {
|
||||
return surface;
|
||||
}
|
||||
|
||||
public boolean isSurfaceReady() {
|
||||
return surfaceReady;
|
||||
}
|
||||
|
||||
/*
|
||||
* Native methods implemented on C++
|
||||
*/
|
||||
public native void onNativeSurfaceChanged();
|
||||
public native void onNativeSurfaceDestroyed();
|
||||
public native void onNativeResize(int width, int height);
|
||||
public native void onNativeTouch(int actionType, float x, float y);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user