2016-05-03 22:24:07 +00:00
|
|
|
package in.celest.xash3d;
|
|
|
|
|
|
|
|
import javax.microedition.khronos.egl.EGL10;
|
|
|
|
import javax.microedition.khronos.egl.EGLConfig;
|
|
|
|
import javax.microedition.khronos.egl.EGLContext;
|
|
|
|
import javax.microedition.khronos.opengles.GL10;
|
|
|
|
import javax.microedition.khronos.egl.*;
|
|
|
|
|
|
|
|
import android.app.*;
|
|
|
|
import android.content.*;
|
|
|
|
import android.view.*;
|
|
|
|
import android.os.*;
|
2016-08-13 00:12:19 +06:00
|
|
|
import android.util.*;
|
2016-05-03 22:24:07 +00:00
|
|
|
import android.graphics.*;
|
|
|
|
import android.text.method.*;
|
|
|
|
import android.text.*;
|
|
|
|
import android.media.*;
|
|
|
|
import android.hardware.*;
|
|
|
|
import android.content.*;
|
2016-05-08 22:57:35 +00:00
|
|
|
import android.widget.*;
|
2016-08-13 00:12:19 +06:00
|
|
|
import android.content.pm.*;
|
2017-03-07 00:00:16 +03:00
|
|
|
import android.net.Uri;
|
|
|
|
import android.provider.*;
|
|
|
|
import android.database.*;
|
2016-05-08 22:57:35 +00:00
|
|
|
|
|
|
|
import android.view.inputmethod.*;
|
2016-05-03 22:24:07 +00:00
|
|
|
|
|
|
|
import java.lang.*;
|
2017-03-30 00:25:51 +00:00
|
|
|
import java.lang.reflect.*;
|
2016-07-28 00:12:01 +06:00
|
|
|
import java.util.List;
|
2016-08-13 00:12:19 +06:00
|
|
|
import java.security.MessageDigest;
|
|
|
|
|
2017-03-07 00:00:16 +03:00
|
|
|
import in.celest.xash3d.hl.R;
|
2016-08-13 00:12:19 +06:00
|
|
|
import in.celest.xash3d.hl.BuildConfig;
|
2016-09-06 20:42:07 +03:00
|
|
|
import in.celest.xash3d.XashConfig;
|
2017-03-04 15:55:06 +03:00
|
|
|
import in.celest.xash3d.JoystickHandler;
|
2017-03-07 00:00:16 +03:00
|
|
|
import in.celest.xash3d.CertCheck;
|
2017-03-28 23:32:39 +00:00
|
|
|
import android.provider.Settings.Secure;
|
2016-05-03 22:24:07 +00:00
|
|
|
|
|
|
|
/**
|
2016-07-28 00:12:01 +06:00
|
|
|
Xash Activity
|
2016-05-03 22:24:07 +00:00
|
|
|
*/
|
|
|
|
public class XashActivity extends Activity {
|
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
// Main components
|
|
|
|
protected static XashActivity mSingleton;
|
|
|
|
protected static View mTextEdit;
|
2017-03-04 17:13:21 +03:00
|
|
|
protected static ViewGroup mLayout;
|
2016-08-01 11:27:51 +00:00
|
|
|
public static EngineSurface mSurface;
|
2016-05-09 14:03:50 +00:00
|
|
|
public static String mArgv[];
|
|
|
|
public static final int sdk = Integer.valueOf(Build.VERSION.SDK);
|
|
|
|
public static final String TAG = "XASH3D:XashActivity";
|
|
|
|
public static int mPixelFormat;
|
2016-08-01 11:27:51 +00:00
|
|
|
public static JoystickHandler handler;
|
2016-08-09 10:50:52 +00:00
|
|
|
public static ImmersiveMode mImmersiveMode;
|
|
|
|
public static boolean keyboardVisible = false;
|
2017-03-07 00:00:16 +03:00
|
|
|
public static boolean mEngineReady = false;
|
2017-03-26 22:11:27 +00:00
|
|
|
public static boolean mEnginePaused = false;
|
|
|
|
public static Vibrator mVibrator;
|
2017-03-30 19:58:11 +00:00
|
|
|
public static boolean fMouseShown = true;
|
2017-03-26 22:11:27 +00:00
|
|
|
|
2017-03-04 15:55:06 +03:00
|
|
|
private static boolean mHasVibrator;
|
2017-03-07 00:00:16 +03:00
|
|
|
private int mReturingWithResultCode = 0;
|
2017-03-06 00:01:39 +03:00
|
|
|
|
|
|
|
private static int OPEN_DOCUMENT_TREE_RESULT = 1;
|
|
|
|
private static int FPICKER_RESULT = 2;
|
2017-03-07 00:00:16 +03:00
|
|
|
|
2016-08-01 11:27:51 +00:00
|
|
|
|
|
|
|
// Joystick constants
|
|
|
|
public final static byte JOY_HAT_CENTERED = 0; // bitmasks for hat current status
|
|
|
|
public final static byte JOY_HAT_UP = 1;
|
|
|
|
public final static byte JOY_HAT_RIGHT = 2;
|
|
|
|
public final static byte JOY_HAT_DOWN = 4;
|
|
|
|
public final static byte JOY_HAT_LEFT = 8;
|
|
|
|
|
|
|
|
public final static byte JOY_AXIS_SIDE = 0; // this represents default
|
|
|
|
public final static byte JOY_AXIS_FWD = 1; // engine binding: SFPYRL
|
|
|
|
public final static byte JOY_AXIS_PITCH = 2;
|
|
|
|
public final static byte JOY_AXIS_YAW = 3;
|
|
|
|
public final static byte JOY_AXIS_RT = 4;
|
|
|
|
public final static byte JOY_AXIS_LT = 5;
|
2016-05-09 14:03:50 +00:00
|
|
|
|
2016-07-26 22:39:54 +06:00
|
|
|
// Preferences
|
2016-05-09 14:03:50 +00:00
|
|
|
public static SharedPreferences mPref = null;
|
2016-05-31 09:03:38 +00:00
|
|
|
private static boolean mUseVolume;
|
2016-08-05 17:43:46 +00:00
|
|
|
public static View mDecorView;
|
2016-08-13 00:12:19 +06:00
|
|
|
|
2016-07-28 00:12:01 +06:00
|
|
|
|
2017-03-02 22:29:30 +03:00
|
|
|
// Load the .so
|
|
|
|
static {
|
2017-03-04 17:13:21 +03:00
|
|
|
System.loadLibrary("gpgs_support");
|
|
|
|
System.loadLibrary("xash");
|
2017-03-02 22:29:30 +03:00
|
|
|
}
|
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
// Setup
|
2016-08-05 19:17:03 +06:00
|
|
|
@Override
|
2016-05-09 14:03:50 +00:00
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
Log.v(TAG, "onCreate()");
|
|
|
|
super.onCreate(savedInstanceState);
|
2017-03-07 00:00:16 +03:00
|
|
|
mEngineReady = false;
|
2016-08-13 00:12:19 +06:00
|
|
|
|
2017-03-07 00:00:16 +03:00
|
|
|
if( CertCheck.dumbAntiPDALifeCheck(this) )
|
2016-08-13 00:12:19 +06:00
|
|
|
{
|
|
|
|
finish();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
// So we can call stuff from static callbacks
|
|
|
|
mSingleton = this;
|
|
|
|
|
|
|
|
// fullscreen
|
2016-05-06 16:49:42 +00:00
|
|
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
2017-03-04 15:55:06 +03:00
|
|
|
|
|
|
|
int flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
|
|
|
|
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
|
|
|
|
getWindow().setFlags(flags, flags);
|
2016-05-06 16:49:42 +00:00
|
|
|
|
2016-05-08 07:59:53 +00:00
|
|
|
// landscapeSensor is not supported until API9
|
|
|
|
if( sdk < 9 )
|
|
|
|
setRequestedOrientation(0);
|
2017-03-06 00:01:39 +03:00
|
|
|
|
|
|
|
mPref = this.getSharedPreferences("engine", 0);
|
2017-03-04 15:55:06 +03:00
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
if( mPref.getBoolean("folderask", true ) )
|
|
|
|
{
|
|
|
|
Log.v(TAG, "folderask == true. Opening FPicker...");
|
2017-03-04 17:13:21 +03:00
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
Intent intent = new Intent(this, in.celest.xash3d.FPicker.class);
|
|
|
|
startActivityForResult( intent, FPICKER_RESULT );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Log.v(TAG, "folderask == false. Checking write permission...");
|
2016-05-06 16:49:42 +00:00
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
// check write permission and run engine, if possible
|
|
|
|
String basedir = getStringExtraFromIntent( getIntent(), "basedir", mPref.getString("basedir","/sdcard/xash/"));
|
|
|
|
checkWritePermission( basedir );
|
|
|
|
}
|
2017-03-04 15:55:06 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
@Override
|
|
|
|
public void onActivityResult(int requestCode, int resultCode, Intent resultData)
|
|
|
|
{
|
|
|
|
if( resultCode != RESULT_OK )
|
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
Log.v(TAG, "onActivityResult: result is not OK. ReqCode: " + requestCode + ". ResCode: " + resultCode);
|
2017-03-06 00:01:39 +03:00
|
|
|
}
|
2017-03-07 00:00:16 +03:00
|
|
|
else
|
2017-03-06 00:01:39 +03:00
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
// it's not possible to create dialogs here
|
|
|
|
// so most work will be done after Activity resuming, in onPostResume()
|
|
|
|
mReturingWithResultCode = requestCode;
|
|
|
|
if( requestCode == FPICKER_RESULT )
|
|
|
|
{
|
|
|
|
String newBaseDir = resultData.getStringExtra("GetPath");
|
|
|
|
setNewBasedir( newBaseDir );
|
|
|
|
setFolderAsk( false ); // don't ask on next run
|
|
|
|
Log.v(TAG, "Got new basedir from FPicker: " + newBaseDir );
|
|
|
|
}
|
2017-03-06 00:01:39 +03:00
|
|
|
}
|
2017-03-07 00:00:16 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPostResume()
|
|
|
|
{
|
|
|
|
super.onPostResume();
|
|
|
|
|
|
|
|
if( mReturingWithResultCode != 0 )
|
2017-03-06 00:01:39 +03:00
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
if( mReturingWithResultCode == FPICKER_RESULT )
|
2017-03-06 00:01:39 +03:00
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
String basedir = mPref.getString( "basedir", "/sdcard/xash/" );
|
|
|
|
checkWritePermission( basedir );
|
|
|
|
}
|
2017-04-01 00:52:13 +03:00
|
|
|
/*else if( mReturingWithResultCode == OPEN_DOCUMENT_TREE_RESULT )
|
2017-03-07 00:00:16 +03:00
|
|
|
{
|
|
|
|
String basedir = getStringExtraFromIntent( getIntent(), "basedir", mPref.getString("basedir","/sdcard/xash/"));
|
|
|
|
Log.v(TAG, "Got permissions. Checking writing again...");
|
|
|
|
|
|
|
|
if( nativeTestWritePermission( basedir ) == 0 )
|
|
|
|
{
|
|
|
|
Log.v(TAG, "Write test has failed twice!");
|
|
|
|
String msg = getString(R.string.lollipop_request_permission_fail_msg) + getString(R.string.ask_about_new_basedir_msg);
|
2017-03-06 00:01:39 +03:00
|
|
|
|
2017-03-07 00:00:16 +03:00
|
|
|
new AlertDialog.Builder(this)
|
|
|
|
.setTitle( R.string.write_failed )
|
|
|
|
.setMessage( msg )
|
|
|
|
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
|
2017-03-06 00:01:39 +03:00
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
public void onClick(DialogInterface dialog, int whichButton)
|
|
|
|
{
|
|
|
|
XashActivity act = XashActivity.this;
|
|
|
|
act.setFolderAsk( true );
|
|
|
|
act.finish();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.setCancelable(false)
|
|
|
|
.show();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
launchSurfaceAndEngine();
|
|
|
|
}
|
2017-04-01 00:52:13 +03:00
|
|
|
}*/
|
2017-03-07 00:00:16 +03:00
|
|
|
|
|
|
|
mReturingWithResultCode = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Events
|
|
|
|
@Override
|
|
|
|
protected void onPause() {
|
|
|
|
Log.v(TAG, "onPause()");
|
|
|
|
|
|
|
|
if( mEngineReady )
|
|
|
|
{
|
|
|
|
// let engine save all configs before exiting.
|
|
|
|
nativeOnPause();
|
|
|
|
|
|
|
|
// wait until Xash will save all configs
|
|
|
|
mSurface.engineThreadWait();
|
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
}
|
2017-03-07 00:00:16 +03:00
|
|
|
|
|
|
|
super.onPause();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onResume() {
|
|
|
|
Log.v(TAG, "onResume()");
|
2017-03-24 22:03:00 +00:00
|
|
|
|
|
|
|
if( mEngineReady )
|
|
|
|
nativeOnResume();
|
|
|
|
|
2017-03-26 22:11:27 +00:00
|
|
|
mEnginePaused = false;
|
|
|
|
|
2017-03-07 00:00:16 +03:00
|
|
|
super.onResume();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onStop() {
|
|
|
|
Log.v(TAG, "onStop()");
|
2017-03-24 22:03:00 +00:00
|
|
|
/*
|
2017-03-07 00:00:16 +03:00
|
|
|
if( mEngineReady )
|
|
|
|
{
|
2017-03-24 22:03:00 +00:00
|
|
|
nativeSetPause(0);
|
2017-03-07 00:00:16 +03:00
|
|
|
// let engine properly exit, instead of killing it's thread
|
|
|
|
nativeOnStop();
|
|
|
|
|
|
|
|
// wait for engine
|
|
|
|
mSurface.engineThreadWait();
|
|
|
|
}
|
2017-03-24 22:03:00 +00:00
|
|
|
*/
|
2017-03-07 00:00:16 +03:00
|
|
|
super.onStop();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onDestroy() {
|
2017-03-24 22:03:00 +00:00
|
|
|
Log.v(TAG, "onDestroy()");
|
2017-03-07 00:00:16 +03:00
|
|
|
|
|
|
|
if( mEngineReady )
|
|
|
|
{
|
2017-03-24 22:03:00 +00:00
|
|
|
nativeUnPause();
|
2017-03-07 00:00:16 +03:00
|
|
|
// let engine a chance to properly exit
|
|
|
|
nativeOnDestroy();
|
2017-03-24 22:03:00 +00:00
|
|
|
|
|
|
|
//mSurface.engineThreadWait();
|
2017-03-07 00:00:16 +03:00
|
|
|
// wait until Xash will exit
|
|
|
|
mSurface.engineThreadJoin();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
super.onDestroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onWindowFocusChanged(boolean hasFocus)
|
|
|
|
{
|
2017-03-24 22:03:00 +00:00
|
|
|
|
|
|
|
if( mEngineReady )
|
|
|
|
nativeOnFocusChange();
|
2017-03-07 00:00:16 +03:00
|
|
|
super.onWindowFocusChanged(hasFocus);
|
|
|
|
|
|
|
|
if( mImmersiveMode != null )
|
|
|
|
mImmersiveMode.apply();
|
2017-03-06 00:01:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public void setFolderAsk( Boolean b )
|
|
|
|
{
|
|
|
|
SharedPreferences.Editor editor = mPref.edit();
|
|
|
|
|
|
|
|
editor.putBoolean( "folderask", b );
|
|
|
|
editor.commit();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setNewBasedir( String baseDir )
|
|
|
|
{
|
|
|
|
SharedPreferences.Editor editor = mPref.edit();
|
|
|
|
|
2017-03-07 00:00:16 +03:00
|
|
|
editor.putString( "basedir", baseDir );
|
2017-03-06 00:01:39 +03:00
|
|
|
editor.commit();
|
|
|
|
}
|
|
|
|
|
2017-03-04 17:13:21 +03:00
|
|
|
private String getStringExtraFromIntent( Intent intent, String extraString, String ifNotFound )
|
|
|
|
{
|
|
|
|
String ret = intent.getStringExtra(extraString);
|
|
|
|
if( ret == null ) ret = ifNotFound;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
private void checkWritePermission( String basedir )
|
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
Log.v(TAG, "Checking write permissions...");
|
|
|
|
|
|
|
|
if( nativeTestWritePermission( basedir ) == 0 )
|
2017-03-06 00:01:39 +03:00
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
Log.v(TAG, "First check has failed!");
|
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
if( sdk > 20 )
|
|
|
|
{
|
2017-04-01 00:52:13 +03:00
|
|
|
// 5.0 and higher _allows_ writing to SD card, but have broken fopen() call. So, no Xash here. F*ck you, Google!
|
|
|
|
String msg = getString(R.string.lollipop_write_fail_msg) + getString(R.string.ask_about_new_basedir_msg);
|
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
new AlertDialog.Builder(this)
|
|
|
|
.setTitle( R.string.write_failed )
|
2017-04-01 00:52:13 +03:00
|
|
|
.setMessage( msg )
|
|
|
|
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
|
2017-03-06 00:01:39 +03:00
|
|
|
{
|
|
|
|
public void onClick(DialogInterface dialog, int whichButton)
|
|
|
|
{
|
2017-04-01 00:52:13 +03:00
|
|
|
XashActivity act = XashActivity.this;
|
|
|
|
act.setFolderAsk( true );
|
|
|
|
act.finish();
|
2017-03-06 00:01:39 +03:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.setCancelable(false)
|
|
|
|
.show();
|
|
|
|
}
|
|
|
|
else if( sdk > 18 )
|
|
|
|
{
|
|
|
|
// 4.4 and 4.4W does not allow SD card write at all
|
|
|
|
String msg = getString(R.string.kitkat_write_fail_msg) + getString(R.string.ask_about_new_basedir_msg);
|
|
|
|
|
|
|
|
new AlertDialog.Builder(this)
|
|
|
|
.setTitle( R.string.write_failed )
|
|
|
|
.setMessage( msg )
|
|
|
|
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
|
|
|
|
{
|
|
|
|
public void onClick(DialogInterface dialog, int whichButton)
|
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
XashActivity act = XashActivity.this;
|
2017-03-06 00:01:39 +03:00
|
|
|
act.setFolderAsk( true );
|
|
|
|
act.finish();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.setCancelable(false)
|
|
|
|
.show();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
String msg = getString(R.string.readonly_fs_fail_msg) + getString(R.string.ask_about_new_basedir_msg);
|
|
|
|
|
|
|
|
// Read-only filesystem
|
|
|
|
// Logically should be never reached
|
|
|
|
new AlertDialog.Builder(this)
|
|
|
|
.setTitle( R.string.write_failed )
|
|
|
|
.setMessage( msg )
|
|
|
|
.setPositiveButton( R.string.ok, new DialogInterface.OnClickListener()
|
|
|
|
{
|
|
|
|
public void onClick(DialogInterface dialog, int whichButton)
|
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
XashActivity act = XashActivity.this;
|
2017-03-06 00:01:39 +03:00
|
|
|
act.setFolderAsk( true );
|
|
|
|
act.finish();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.setCancelable(false)
|
|
|
|
.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// everything is normal, so launch engine
|
|
|
|
launchSurfaceAndEngine();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void launchSurfaceAndEngine()
|
|
|
|
{
|
2017-03-07 00:00:16 +03:00
|
|
|
Log.v(TAG, "Everything is OK. Launching engine...");
|
|
|
|
|
2017-03-06 00:01:39 +03:00
|
|
|
setupEnvironment();
|
|
|
|
InstallReceiver.extractPAK(this, false);
|
|
|
|
|
|
|
|
// Set up the surface
|
|
|
|
mSurface = new EngineSurface(getApplication());
|
|
|
|
|
|
|
|
mLayout = new FrameLayout(this);
|
|
|
|
mLayout.addView(mSurface);
|
|
|
|
setContentView(mLayout);
|
|
|
|
|
|
|
|
SurfaceHolder holder = mSurface.getHolder();
|
|
|
|
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
|
|
|
|
|
2017-03-30 23:32:27 +00:00
|
|
|
if( sdk >= 14 )
|
|
|
|
handler = new JoystickHandler_v14();
|
|
|
|
else if( sdk >= 12 )
|
2017-03-07 00:00:16 +03:00
|
|
|
handler = new JoystickHandler_v12();
|
2017-03-30 23:32:27 +00:00
|
|
|
else
|
|
|
|
handler = new JoystickHandler();
|
2017-03-07 00:00:16 +03:00
|
|
|
handler.init();
|
|
|
|
|
|
|
|
mPixelFormat = mPref.getInt("pixelformat", 0);
|
|
|
|
mUseVolume = mPref.getBoolean("usevolume", false);
|
|
|
|
if( mPref.getBoolean("enableResizeWorkaround", true) )
|
|
|
|
AndroidBug5497Workaround.assistActivity(this);
|
|
|
|
|
|
|
|
// Immersive Mode is available only at >KitKat
|
|
|
|
Boolean enableImmersive = (sdk >= 19) && (mPref.getBoolean("immersive_mode", true));
|
|
|
|
if( enableImmersive )
|
|
|
|
mImmersiveMode = new ImmersiveMode_v19();
|
|
|
|
|
|
|
|
mDecorView = getWindow().getDecorView();
|
|
|
|
|
|
|
|
mVibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
|
|
|
|
|
2017-03-26 22:11:27 +00:00
|
|
|
mHasVibrator = ( mVibrator != null );
|
|
|
|
if( sdk >= 11 )
|
|
|
|
mHasVibrator = ( mVibrator != null ) && ( handler.hasVibrator() );
|
|
|
|
|
|
|
|
if( sdk >= 5 )
|
|
|
|
startService(new Intent(getBaseContext(), XashService.class));
|
2017-03-24 22:03:00 +00:00
|
|
|
|
2017-03-07 00:00:16 +03:00
|
|
|
mEngineReady = true;
|
2017-03-06 00:01:39 +03:00
|
|
|
}
|
|
|
|
|
2017-03-04 15:55:06 +03:00
|
|
|
private void setupEnvironment()
|
|
|
|
{
|
|
|
|
Intent intent = getIntent();
|
|
|
|
final String enginedir = getFilesDir().getParentFile().getPath() + "/lib";
|
2017-03-06 00:01:39 +03:00
|
|
|
|
2017-03-04 17:13:21 +03:00
|
|
|
String argv = getStringExtraFromIntent(intent, "argv", mPref.getString("argv", "-dev 3 -log"));
|
|
|
|
String gamelibdir = getStringExtraFromIntent(intent, "gamelibdir", enginedir);
|
|
|
|
String gamedir = getStringExtraFromIntent(intent, "gamedir", "valve");
|
|
|
|
String basedir = getStringExtraFromIntent(intent, "basedir", mPref.getString("basedir","/sdcard/xash/"));
|
2017-03-04 15:55:06 +03:00
|
|
|
|
2017-03-02 21:33:27 +03:00
|
|
|
mArgv = argv.split(" ");
|
2016-05-09 14:03:50 +00:00
|
|
|
|
2017-03-04 15:55:06 +03:00
|
|
|
setenv("XASH3D_BASEDIR", basedir, true);
|
|
|
|
setenv("XASH3D_ENGLIBDIR", enginedir, true);
|
2016-05-04 21:02:09 +00:00
|
|
|
setenv("XASH3D_GAMELIBDIR", gamelibdir, true);
|
2017-03-04 15:55:06 +03:00
|
|
|
setenv("XASH3D_GAMEDIR", gamedir, true);
|
2016-05-04 21:02:09 +00:00
|
|
|
setenv("XASH3D_EXTRAS_PAK1", getFilesDir().getPath() + "/extras.pak", true);
|
2017-03-04 15:55:06 +03:00
|
|
|
|
2016-05-04 21:02:09 +00:00
|
|
|
String pakfile = intent.getStringExtra("pakfile");
|
|
|
|
if( pakfile != null && pakfile != "" )
|
|
|
|
setenv("XASH3D_EXTRAS_PAK2", pakfile, true);
|
2017-03-02 21:33:27 +03:00
|
|
|
|
2016-05-04 21:02:09 +00:00
|
|
|
String[] env = intent.getStringArrayExtra("env");
|
2017-03-02 21:33:27 +03:00
|
|
|
if( env != null )
|
2016-05-04 21:02:09 +00:00
|
|
|
{
|
2017-03-02 21:33:27 +03:00
|
|
|
try
|
2016-05-04 21:02:09 +00:00
|
|
|
{
|
2017-03-02 21:33:27 +03:00
|
|
|
for(int i = 0; i+1 < env.length; i+=2)
|
|
|
|
{
|
2017-03-04 15:55:06 +03:00
|
|
|
setenv(env[i], env[i+1], true);
|
2017-03-02 21:33:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
|
|
|
e.printStackTrace();
|
2016-05-04 21:02:09 +00:00
|
|
|
}
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-04 15:55:06 +03:00
|
|
|
public static native int nativeInit(Object arguments);
|
2016-05-09 14:03:50 +00:00
|
|
|
public static native void nativeQuit();
|
|
|
|
public static native void onNativeResize(int x, int y);
|
|
|
|
public static native void nativeTouch(int pointerFingerId, int action, float x, float y);
|
|
|
|
public static native void nativeKey( int down, int code );
|
|
|
|
public static native void nativeString( String text );
|
|
|
|
public static native void nativeSetPause(int pause);
|
2017-03-04 15:55:06 +03:00
|
|
|
public static native void nativeOnDestroy();
|
2017-03-24 22:03:00 +00:00
|
|
|
public static native void nativeOnResume();
|
|
|
|
public static native void nativeOnFocusChange();
|
2017-03-04 15:55:06 +03:00
|
|
|
public static native void nativeOnPause();
|
2017-03-24 22:03:00 +00:00
|
|
|
public static native void nativeUnPause();
|
2016-07-28 00:12:01 +06:00
|
|
|
public static native void nativeHat(int id, byte hat, byte keycode, boolean down);
|
2016-07-26 22:39:54 +06:00
|
|
|
public static native void nativeAxis(int id, byte axis, short value);
|
2016-07-28 00:12:01 +06:00
|
|
|
public static native void nativeJoyButton(int id, byte button, boolean down);
|
2017-03-06 00:01:39 +03:00
|
|
|
public static native int nativeTestWritePermission( String path );
|
2017-03-30 00:25:51 +00:00
|
|
|
public static native void nativeMouseMove( float x, float y );
|
2016-07-26 22:39:54 +06:00
|
|
|
|
|
|
|
// for future expansion
|
|
|
|
public static native void nativeBall(int id, byte ball, short xrel, short yrel);
|
|
|
|
public static native void nativeJoyAdd( int id );
|
|
|
|
public static native void nativeJoyDel( int id );
|
|
|
|
|
2017-03-04 15:55:06 +03:00
|
|
|
// libjnisetenv
|
2016-05-09 14:03:50 +00:00
|
|
|
public static native int setenv(String key, String value, boolean overwrite);
|
|
|
|
|
|
|
|
// Java functions called from C
|
|
|
|
|
|
|
|
public static boolean createGLContext() {
|
|
|
|
return mSurface.InitGL();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void swapBuffers() {
|
|
|
|
mSurface.SwapBuffers();
|
|
|
|
}
|
2017-03-04 00:56:51 +03:00
|
|
|
|
|
|
|
public static void engineThreadNotify() {
|
|
|
|
mSurface.engineThreadNotify();
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
|
2016-05-12 22:42:15 +00:00
|
|
|
public static Surface getNativeSurface() {
|
|
|
|
return XashActivity.mSurface.getNativeSurface();
|
|
|
|
}
|
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
public static void vibrate( int time ) {
|
2017-03-04 15:55:06 +03:00
|
|
|
if( mHasVibrator ) mVibrator.vibrate( time );
|
2016-05-09 14:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void toggleEGL(int toggle) {
|
|
|
|
mSurface.toggleEGL(toggle);
|
|
|
|
}
|
2016-08-05 19:17:03 +06:00
|
|
|
|
|
|
|
public static boolean deleteGLContext() {
|
|
|
|
mSurface.ShutdownGL();
|
|
|
|
return true;
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
|
|
|
|
public static Context getContext() {
|
|
|
|
return mSingleton;
|
|
|
|
}
|
2017-03-04 15:55:06 +03:00
|
|
|
|
2016-05-09 15:05:28 +00:00
|
|
|
protected final String[] messageboxData = new String[2];
|
|
|
|
public static void messageBox(String title, String text)
|
|
|
|
{
|
|
|
|
mSingleton.messageboxData[0] = title;
|
|
|
|
mSingleton.messageboxData[1] = text;
|
|
|
|
mSingleton.runOnUiThread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run()
|
|
|
|
{
|
|
|
|
new AlertDialog.Builder(mSingleton)
|
|
|
|
.setTitle(mSingleton.messageboxData[0])
|
|
|
|
.setMessage(mSingleton.messageboxData[1])
|
|
|
|
.setPositiveButton( "Ok", new DialogInterface.OnClickListener() {
|
|
|
|
public void onClick(DialogInterface dialog, int whichButton) {
|
|
|
|
synchronized(mSingleton.messageboxData)
|
|
|
|
{
|
|
|
|
mSingleton.messageboxData.notify();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.setCancelable(false)
|
|
|
|
.show();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
synchronized (mSingleton.messageboxData) {
|
|
|
|
try {
|
|
|
|
mSingleton.messageboxData.wait();
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
ex.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
|
|
|
|
public static boolean handleKey( int keyCode, KeyEvent event )
|
|
|
|
{
|
2016-07-26 22:39:54 +06:00
|
|
|
if ( mUseVolume && ( keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
|
2016-05-31 09:03:38 +00:00
|
|
|
keyCode == KeyEvent.KEYCODE_VOLUME_UP ) )
|
2016-07-26 22:39:54 +06:00
|
|
|
return false;
|
|
|
|
|
2016-08-01 11:27:51 +00:00
|
|
|
final int source = XashActivity.handler.getSource(event);
|
2016-07-28 00:12:01 +06:00
|
|
|
final int action = event.getAction();
|
|
|
|
final boolean isGamePad = (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD;
|
|
|
|
final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK;
|
|
|
|
final boolean isDPad = (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD;
|
2016-08-01 19:11:11 +00:00
|
|
|
|
|
|
|
if( isDPad )
|
|
|
|
{
|
|
|
|
byte val;
|
|
|
|
final byte hat = 0;
|
|
|
|
final int id = 0;
|
|
|
|
Log.d(TAG, "DPAD button: " + keyCode );
|
|
|
|
switch( keyCode )
|
|
|
|
{
|
|
|
|
case KeyEvent.KEYCODE_DPAD_CENTER: val = JOY_HAT_CENTERED; break;
|
|
|
|
case KeyEvent.KEYCODE_DPAD_UP: val = JOY_HAT_UP; break;
|
|
|
|
case KeyEvent.KEYCODE_DPAD_RIGHT: val = JOY_HAT_RIGHT; break;
|
|
|
|
case KeyEvent.KEYCODE_DPAD_DOWN: val = JOY_HAT_DOWN; break;
|
|
|
|
case KeyEvent.KEYCODE_DPAD_LEFT: val = JOY_HAT_LEFT; break;
|
2016-08-12 14:30:42 +00:00
|
|
|
default: return performEngineKeyEvent( action, keyCode, event );
|
2016-08-01 19:11:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(action == KeyEvent.ACTION_DOWN)
|
|
|
|
nativeHat(id, hat, val, true);
|
|
|
|
else if(action == KeyEvent.ACTION_UP)
|
|
|
|
nativeHat(id, hat, val, false);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-28 00:12:01 +06:00
|
|
|
// Engine will bind these to AUX${val} virtual keys
|
2016-09-06 20:14:11 +03:00
|
|
|
// Android may send event without source flags set to GAMEPAD or CLASS_JOYSTICK
|
|
|
|
// so check for gamepad buttons anyway
|
|
|
|
if( isGamePad || isJoystick || XashActivity.handler.isGamepadButton( keyCode ) )
|
2016-07-26 22:39:54 +06:00
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
final int id = 0;
|
|
|
|
byte val = 15;
|
2016-07-26 22:39:54 +06:00
|
|
|
|
|
|
|
switch( keyCode )
|
|
|
|
{
|
|
|
|
// main buttons. DONT CHANGE THIS!!!!111oneone
|
2016-07-28 00:12:01 +06:00
|
|
|
case KeyEvent.KEYCODE_BUTTON_A: val = 0; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_B: val = 1; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_X: val = 2; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_Y: val = 3; break;
|
2016-09-06 20:14:11 +03:00
|
|
|
case KeyEvent.KEYCODE_BUTTON_L1: val = 4; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_R1: val = 5; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_SELECT: val = 6; break;
|
2016-07-28 00:12:01 +06:00
|
|
|
case KeyEvent.KEYCODE_BUTTON_MODE: val = 7; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_START: val = 8; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_THUMBL: val = 9; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_THUMBR: val = 10; break;
|
2016-07-26 22:39:54 +06:00
|
|
|
|
|
|
|
// other
|
2016-07-28 00:12:01 +06:00
|
|
|
case KeyEvent.KEYCODE_BUTTON_C: val = 11; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_Z: val = 12; break;
|
2016-09-06 20:14:11 +03:00
|
|
|
case KeyEvent.KEYCODE_BUTTON_L2: val = 13; break;
|
|
|
|
case KeyEvent.KEYCODE_BUTTON_R2: val = 14; break;
|
2016-07-26 22:39:54 +06:00
|
|
|
default:
|
|
|
|
if( keyCode >= KeyEvent.KEYCODE_BUTTON_1 && keyCode <= KeyEvent.KEYCODE_BUTTON_16 )
|
|
|
|
{
|
2016-09-06 20:14:11 +03:00
|
|
|
val = (byte)((keyCode - KeyEvent.KEYCODE_BUTTON_1) + 15);
|
2016-07-26 22:39:54 +06:00
|
|
|
}
|
2016-08-01 11:27:51 +00:00
|
|
|
else if( XashActivity.handler.isGamepadButton(keyCode) )
|
2016-07-26 22:39:54 +06:00
|
|
|
{
|
2016-09-06 20:14:11 +03:00
|
|
|
// maybe never reached, as all possible gamepad buttons are checked before
|
2016-08-01 11:27:51 +00:00
|
|
|
Log.d(TAG, "Unhandled GamePad button: " + XashActivity.handler.keyCodeToString(keyCode) );
|
2016-07-26 22:39:54 +06:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-01 19:11:11 +00:00
|
|
|
else
|
|
|
|
{
|
2016-09-06 20:14:11 +03:00
|
|
|
// must be never reached too
|
|
|
|
return performEngineKeyEvent( action, keyCode, event );
|
2016-08-01 19:11:11 +00:00
|
|
|
}
|
2016-07-26 22:39:54 +06:00
|
|
|
}
|
2016-07-28 00:12:01 +06:00
|
|
|
|
2017-04-05 22:03:19 +00:00
|
|
|
if( action == KeyEvent.ACTION_DOWN )
|
2016-09-06 20:14:11 +03:00
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
nativeJoyButton( id, val, true );
|
2016-09-06 20:14:11 +03:00
|
|
|
return true;
|
|
|
|
}
|
2017-04-05 22:03:19 +00:00
|
|
|
else if( action == KeyEvent.ACTION_UP )
|
2016-09-06 20:14:11 +03:00
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
nativeJoyButton( id, val, false );
|
2016-09-06 20:14:11 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2016-07-26 22:39:54 +06:00
|
|
|
}
|
2016-08-01 19:11:11 +00:00
|
|
|
|
2016-08-12 14:30:42 +00:00
|
|
|
return performEngineKeyEvent( action, keyCode, event );
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean performEngineKeyEvent( int action, int keyCode, KeyEvent event)
|
|
|
|
{
|
2017-04-05 22:03:19 +00:00
|
|
|
Log.v(TAG, "EngineKeyEvent( " + action +", " + keyCode +" "+ event.isCtrlPressed() +" )");
|
|
|
|
|
|
|
|
|
2016-08-12 14:30:42 +00:00
|
|
|
if( action == KeyEvent.ACTION_DOWN )
|
2016-05-09 14:03:50 +00:00
|
|
|
{
|
2016-08-12 14:30:42 +00:00
|
|
|
if( event.isPrintingKey() || keyCode == 62 )// space is printing too
|
|
|
|
XashActivity.nativeString( String.valueOf( (char) event.getUnicodeChar() ) );
|
2016-05-09 14:03:50 +00:00
|
|
|
|
2016-08-12 14:30:42 +00:00
|
|
|
XashActivity.nativeKey( 1, keyCode );
|
2016-05-09 14:03:50 +00:00
|
|
|
|
2016-05-08 22:57:35 +00:00
|
|
|
return true;
|
2016-05-09 14:03:50 +00:00
|
|
|
}
|
2016-08-12 14:30:42 +00:00
|
|
|
else if( action == KeyEvent.ACTION_UP )
|
2016-05-09 14:03:50 +00:00
|
|
|
{
|
2017-04-05 22:03:19 +00:00
|
|
|
if( keyCode == 62 && event.isCtrlPressed() )
|
|
|
|
XashActivity.nativeKey( 1, keyCode );
|
2016-08-12 14:30:42 +00:00
|
|
|
XashActivity.nativeKey( 0, keyCode );
|
2016-05-08 22:57:35 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2016-07-26 22:39:54 +06:00
|
|
|
|
2016-08-01 11:27:51 +00:00
|
|
|
public static float performEngineAxisEvent( float current, byte engineAxis, float prev, float flat )
|
2016-07-26 22:39:54 +06:00
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
if( prev != current )
|
2016-07-26 22:39:54 +06:00
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
final int id = 0;
|
|
|
|
final short SHRT_MAX = 32767;
|
|
|
|
if( current <= flat && current >= -flat )
|
|
|
|
current = 0;
|
|
|
|
|
|
|
|
nativeAxis( id, engineAxis, (short)(current * SHRT_MAX) );
|
2016-07-26 22:39:54 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
return current;
|
|
|
|
}
|
|
|
|
|
2016-08-01 11:27:51 +00:00
|
|
|
public static float performEngineHatEvent( float curr, boolean isXAxis, float prev )
|
2016-07-26 22:39:54 +06:00
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
if( prev != curr )
|
2016-07-26 22:39:54 +06:00
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
final int id = 0;
|
|
|
|
final byte hat = 0;
|
|
|
|
if( isXAxis )
|
|
|
|
{
|
|
|
|
if( curr > 0 ) nativeHat( id, hat, JOY_HAT_RIGHT, true );
|
|
|
|
else if( curr < 0 ) nativeHat( id, hat, JOY_HAT_LEFT, true );
|
|
|
|
// unpress previous if curr centered
|
|
|
|
else if( prev > 0 ) nativeHat( id, hat, JOY_HAT_RIGHT, false );
|
|
|
|
else if( prev < 0 ) nativeHat( id, hat, JOY_HAT_LEFT, false );
|
|
|
|
}
|
2016-07-26 22:39:54 +06:00
|
|
|
else
|
|
|
|
{
|
2016-07-28 00:12:01 +06:00
|
|
|
if( curr > 0 ) nativeHat( id, hat, JOY_HAT_DOWN, true );
|
|
|
|
else if( curr < 0 ) nativeHat( id, hat, JOY_HAT_UP, true );
|
|
|
|
// unpress previous if curr centered
|
|
|
|
else if( prev > 0 ) nativeHat( id, hat, JOY_HAT_DOWN, false );
|
|
|
|
else if( prev < 0 ) nativeHat( id, hat, JOY_HAT_UP, false );
|
2016-07-26 22:39:54 +06:00
|
|
|
}
|
|
|
|
}
|
2016-07-28 00:12:01 +06:00
|
|
|
return curr;
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
|
|
|
|
static class ShowTextInputTask implements Runnable
|
|
|
|
{
|
2016-05-08 22:57:35 +00:00
|
|
|
/*
|
|
|
|
* This is used to regulate the pan&scan method to have some offset from
|
|
|
|
* the bottom edge of the input region and the top edge of an input
|
|
|
|
* method (soft keyboard)
|
|
|
|
*/
|
|
|
|
private int show;
|
|
|
|
|
|
|
|
public ShowTextInputTask(int show1) {
|
|
|
|
show = show1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
|
|
|
|
|
|
|
|
if (mTextEdit == null)
|
|
|
|
{
|
|
|
|
mTextEdit = new DummyEdit(getContext());
|
|
|
|
mLayout.addView(mTextEdit);
|
|
|
|
}
|
|
|
|
if( show == 1 )
|
|
|
|
{
|
2016-05-09 14:03:50 +00:00
|
|
|
mTextEdit.setVisibility(View.VISIBLE);
|
|
|
|
mTextEdit.requestFocus();
|
2016-05-08 22:57:35 +00:00
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
imm.showSoftInput(mTextEdit, 0);
|
2016-08-09 10:50:52 +00:00
|
|
|
keyboardVisible = true;
|
|
|
|
if( XashActivity.mImmersiveMode != null )
|
|
|
|
XashActivity.mImmersiveMode.apply();
|
2016-05-08 22:57:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mTextEdit.setVisibility(View.GONE);
|
|
|
|
imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
|
2016-08-09 10:50:52 +00:00
|
|
|
keyboardVisible = false;
|
|
|
|
if( XashActivity.mImmersiveMode != null )
|
|
|
|
XashActivity.mImmersiveMode.apply();
|
2016-05-08 22:57:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-07-28 00:12:01 +06:00
|
|
|
* This method is called by engine using JNI.
|
2016-05-08 22:57:35 +00:00
|
|
|
*/
|
2016-05-09 14:03:50 +00:00
|
|
|
public static void showKeyboard( int show )
|
|
|
|
{
|
2016-05-08 22:57:35 +00:00
|
|
|
// Transfer the task to the main thread as a Runnable
|
|
|
|
mSingleton.runOnUiThread(new ShowTextInputTask(show));
|
|
|
|
}
|
|
|
|
|
2017-03-26 22:11:27 +00:00
|
|
|
public static void setIcon(String path)
|
|
|
|
{
|
|
|
|
Log.v(TAG,"setIcon("+path+")");
|
|
|
|
if( sdk < 5 )
|
|
|
|
return;
|
|
|
|
try{
|
|
|
|
BitmapFactory.Options o = new BitmapFactory.Options();
|
|
|
|
o.inJustDecodeBounds = true;
|
|
|
|
Bitmap icon = BitmapFactory.decodeFile(path,o);
|
|
|
|
if( icon.getWidth() < 16 )
|
|
|
|
return;
|
|
|
|
XashService.notification.contentView.setImageViewUri (XashService.status_image, Uri.parse("file://"+path));
|
|
|
|
((NotificationManager) mSingleton.getApplicationContext()
|
|
|
|
.getSystemService(Context.NOTIFICATION_SERVICE)).notify(100,XashService.notification);
|
|
|
|
}
|
|
|
|
catch( Exception e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setTitle(String title)
|
|
|
|
{
|
|
|
|
Log.v(TAG,"setTitle("+title+")");
|
|
|
|
if( sdk < 5 )
|
|
|
|
return;
|
|
|
|
XashService.notification.contentView.setTextViewText(XashService.status_text, title);
|
|
|
|
((NotificationManager) mSingleton.getApplicationContext()
|
|
|
|
.getSystemService(Context.NOTIFICATION_SERVICE)).notify(100,XashService.notification);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-03-28 23:32:39 +00:00
|
|
|
public static String getAndroidID()
|
|
|
|
{
|
|
|
|
String str = Secure.getString( mSingleton.getContentResolver(), Secure.ANDROID_ID );
|
|
|
|
if( str == null )
|
|
|
|
return "";
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String loadID()
|
|
|
|
{
|
|
|
|
return mPref.getString("xash_id", "");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void saveID(String id)
|
|
|
|
{
|
|
|
|
SharedPreferences.Editor editor = mPref.edit();
|
|
|
|
|
|
|
|
editor.putString( "xash_id", id );
|
|
|
|
editor.commit();
|
|
|
|
}
|
2017-03-30 00:25:51 +00:00
|
|
|
|
|
|
|
public static void showMouse( int show )
|
|
|
|
{
|
2017-03-30 19:58:11 +00:00
|
|
|
fMouseShown = show != 0;
|
2017-03-30 00:25:51 +00:00
|
|
|
handler.showMouse( show != 0 );
|
|
|
|
}
|
2016-05-03 22:24:07 +00:00
|
|
|
}
|
|
|
|
|
2017-03-24 22:03:00 +00:00
|
|
|
|
2016-05-03 22:24:07 +00:00
|
|
|
/**
|
|
|
|
Simple nativeInit() runnable
|
|
|
|
*/
|
|
|
|
class XashMain implements Runnable {
|
2016-05-09 14:03:50 +00:00
|
|
|
public void run()
|
|
|
|
{
|
|
|
|
XashActivity.nativeInit(XashActivity.mArgv);
|
|
|
|
}
|
2016-05-03 22:24:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-07-28 00:12:01 +06:00
|
|
|
EngineSurface. This is what we draw on, so we need to know when it's created
|
2016-05-04 21:02:09 +00:00
|
|
|
in order to do anything useful.
|
2016-05-03 22:24:07 +00:00
|
|
|
|
2016-07-28 00:12:01 +06:00
|
|
|
Because of this, that's where we set up the Xash3D thread
|
2016-05-03 22:24:07 +00:00
|
|
|
*/
|
2017-03-04 15:55:06 +03:00
|
|
|
class EngineSurface extends SurfaceView implements SurfaceHolder.Callback, View.OnKeyListener
|
|
|
|
{
|
2016-05-03 22:24:07 +00:00
|
|
|
|
2016-07-28 00:12:01 +06:00
|
|
|
// This is what Xash3D runs in. It invokes main(), eventually
|
2016-08-09 10:50:52 +00:00
|
|
|
private static Thread mEngThread = null;
|
2017-03-04 15:55:06 +03:00
|
|
|
private static Object mPauseLock = new Object();
|
2016-05-09 14:03:50 +00:00
|
|
|
|
|
|
|
// EGL private objects
|
|
|
|
private EGLContext mEGLContext;
|
|
|
|
private EGLSurface mEGLSurface;
|
|
|
|
private EGLDisplay mEGLDisplay;
|
|
|
|
private EGL10 mEGL;
|
|
|
|
private EGLConfig mEGLConfig;
|
|
|
|
public static final String TAG = "XASH3D-EngineSurface";
|
|
|
|
|
|
|
|
// Sensors
|
|
|
|
|
|
|
|
// Startup
|
|
|
|
public EngineSurface(Context context)
|
|
|
|
{
|
|
|
|
super(context);
|
|
|
|
getHolder().addCallback(this);
|
|
|
|
|
|
|
|
setFocusable(true);
|
|
|
|
setFocusableInTouchMode(true);
|
|
|
|
requestFocus();
|
|
|
|
setOnKeyListener(this);
|
|
|
|
if( XashActivity.sdk >= 5 )
|
|
|
|
setOnTouchListener(new EngineTouchListener_v5());
|
|
|
|
else
|
|
|
|
setOnTouchListener(new EngineTouchListener_v1());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called when we have a valid drawing surface
|
|
|
|
public void surfaceCreated(SurfaceHolder holder)
|
|
|
|
{
|
|
|
|
Log.v(TAG, "surfaceCreated()");
|
|
|
|
if( mEGL == null )
|
|
|
|
return;
|
|
|
|
XashActivity.nativeSetPause(0);
|
2017-03-26 22:11:27 +00:00
|
|
|
XashActivity.mEnginePaused = false;
|
2016-05-09 14:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Called when we lose the surface
|
|
|
|
public void surfaceDestroyed(SurfaceHolder holder)
|
|
|
|
{
|
|
|
|
Log.v(TAG, "surfaceDestroyed()");
|
|
|
|
if( mEGL == null )
|
|
|
|
return;
|
|
|
|
XashActivity.nativeSetPause(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Called when the surface is resized
|
|
|
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
|
|
|
{
|
|
|
|
Log.v(TAG, "surfaceChanged()");
|
|
|
|
|
|
|
|
XashActivity.onNativeResize(width, height);
|
|
|
|
// Now start up the C app thread
|
|
|
|
if (mEngThread == null) {
|
|
|
|
|
|
|
|
mEngThread = new Thread(new XashMain(), "EngineThread");
|
|
|
|
mEngThread.start();
|
|
|
|
}
|
|
|
|
}
|
2017-03-04 00:21:29 +03:00
|
|
|
|
|
|
|
public void engineThreadJoin()
|
|
|
|
{
|
|
|
|
Log.v(TAG, "engineThreadJoin()");
|
|
|
|
try
|
|
|
|
{
|
|
|
|
mEngThread.join(); // wait until Xash will quit
|
|
|
|
}
|
|
|
|
catch(InterruptedException e)
|
|
|
|
{
|
|
|
|
}
|
2017-03-04 00:56:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public void engineThreadWait()
|
|
|
|
{
|
|
|
|
Log.v(TAG, "engineThreadWait()");
|
2017-03-04 15:55:06 +03:00
|
|
|
synchronized(mPauseLock)
|
2017-03-04 00:56:51 +03:00
|
|
|
{
|
2017-03-04 15:55:06 +03:00
|
|
|
try
|
|
|
|
{
|
|
|
|
mPauseLock.wait(); // wait until Xash will quit
|
|
|
|
}
|
|
|
|
catch(InterruptedException e)
|
|
|
|
{
|
|
|
|
}
|
2017-03-04 00:56:51 +03:00
|
|
|
}
|
2017-03-04 15:55:06 +03:00
|
|
|
|
2017-03-04 00:56:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public void engineThreadNotify()
|
|
|
|
{
|
|
|
|
Log.v(TAG, "engineThreadNotify()");
|
2017-03-04 15:55:06 +03:00
|
|
|
synchronized(mPauseLock)
|
|
|
|
{
|
|
|
|
mPauseLock.notify(); // wait until Xash will quit
|
|
|
|
}
|
2017-03-04 00:21:29 +03:00
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
|
|
|
|
// unused
|
|
|
|
public void onDraw(Canvas canvas) {}
|
|
|
|
|
2016-05-12 22:42:15 +00:00
|
|
|
// first, initialize native backend
|
2016-12-07 00:25:09 +03:00
|
|
|
public Surface getNativeSurface()
|
|
|
|
{
|
2016-05-12 22:42:15 +00:00
|
|
|
return getHolder().getSurface();
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
|
|
|
|
// EGL functions
|
|
|
|
public boolean InitGL() {
|
|
|
|
try
|
|
|
|
{
|
|
|
|
EGL10 egl = (EGL10)EGLContext.getEGL();
|
2016-12-07 00:25:09 +03:00
|
|
|
|
|
|
|
if( egl == null )
|
|
|
|
{
|
|
|
|
Log.e( TAG, "Cannot get EGL from context" );
|
|
|
|
return false;
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
|
|
|
|
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
|
|
|
|
2016-12-07 00:25:09 +03:00
|
|
|
if( dpy == null )
|
|
|
|
{
|
|
|
|
Log.e( TAG, "Cannot get display" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
int[] version = new int[2];
|
2016-12-07 00:25:09 +03:00
|
|
|
if( !egl.eglInitialize(dpy, version) )
|
|
|
|
{
|
|
|
|
Log.e(TAG, "No EGL config available");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int[][] configSpec =
|
|
|
|
{{
|
2016-05-09 14:03:50 +00:00
|
|
|
EGL10.EGL_DEPTH_SIZE, 8,
|
|
|
|
EGL10.EGL_RED_SIZE, 8,
|
|
|
|
EGL10.EGL_GREEN_SIZE, 8,
|
|
|
|
EGL10.EGL_BLUE_SIZE, 8,
|
|
|
|
EGL10.EGL_ALPHA_SIZE, 8,
|
|
|
|
EGL10.EGL_NONE
|
|
|
|
}, {
|
|
|
|
EGL10.EGL_DEPTH_SIZE, 8,
|
|
|
|
EGL10.EGL_RED_SIZE, 8,
|
|
|
|
EGL10.EGL_GREEN_SIZE, 8,
|
|
|
|
EGL10.EGL_BLUE_SIZE, 8,
|
|
|
|
EGL10.EGL_ALPHA_SIZE, 0,
|
|
|
|
EGL10.EGL_NONE
|
|
|
|
}, {
|
|
|
|
EGL10.EGL_DEPTH_SIZE, 8,
|
|
|
|
EGL10.EGL_RED_SIZE, 5,
|
|
|
|
EGL10.EGL_GREEN_SIZE, 6,
|
|
|
|
EGL10.EGL_BLUE_SIZE, 5,
|
|
|
|
EGL10.EGL_ALPHA_SIZE, 0,
|
|
|
|
EGL10.EGL_NONE
|
|
|
|
}, {
|
|
|
|
EGL10.EGL_DEPTH_SIZE, 8,
|
|
|
|
EGL10.EGL_RED_SIZE, 5,
|
|
|
|
EGL10.EGL_GREEN_SIZE, 5,
|
|
|
|
EGL10.EGL_BLUE_SIZE, 5,
|
|
|
|
EGL10.EGL_ALPHA_SIZE, 1,
|
|
|
|
|
|
|
|
EGL10.EGL_NONE
|
|
|
|
}, {
|
|
|
|
EGL10.EGL_DEPTH_SIZE, 8,
|
|
|
|
EGL10.EGL_RED_SIZE, 4,
|
|
|
|
EGL10.EGL_GREEN_SIZE, 4,
|
|
|
|
EGL10.EGL_BLUE_SIZE, 4,
|
|
|
|
EGL10.EGL_ALPHA_SIZE, 4,
|
|
|
|
|
|
|
|
EGL10.EGL_NONE
|
|
|
|
}, {
|
|
|
|
EGL10.EGL_DEPTH_SIZE, 8,
|
|
|
|
EGL10.EGL_RED_SIZE, 3,
|
|
|
|
EGL10.EGL_GREEN_SIZE, 3,
|
|
|
|
EGL10.EGL_BLUE_SIZE, 2,
|
|
|
|
EGL10.EGL_ALPHA_SIZE, 0,
|
|
|
|
|
|
|
|
EGL10.EGL_NONE
|
|
|
|
}};
|
|
|
|
EGLConfig[] configs = new EGLConfig[1];
|
|
|
|
int[] num_config = new int[1];
|
|
|
|
if (!egl.eglChooseConfig(dpy, configSpec[XashActivity.mPixelFormat], configs, 1, num_config) || num_config[0] == 0)
|
|
|
|
{
|
|
|
|
Log.e(TAG, "No EGL config available");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
EGLConfig config = configs[0];
|
|
|
|
|
2016-12-07 00:25:09 +03:00
|
|
|
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
2016-05-09 14:03:50 +00:00
|
|
|
int contextAttrs[] = new int[]
|
|
|
|
{
|
|
|
|
EGL_CONTEXT_CLIENT_VERSION, 1,
|
|
|
|
EGL10.EGL_NONE
|
|
|
|
};
|
|
|
|
EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, contextAttrs);
|
|
|
|
if (ctx == EGL10.EGL_NO_CONTEXT) {
|
|
|
|
Log.e(TAG, "Couldn't create context");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null);
|
|
|
|
if (surface == EGL10.EGL_NO_SURFACE) {
|
|
|
|
Log.e(TAG, "Couldn't create surface");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!egl.eglMakeCurrent(dpy, surface, surface, ctx)) {
|
|
|
|
Log.e(TAG, "Couldn't make context current");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mEGLContext = ctx;
|
|
|
|
mEGLDisplay = dpy;
|
|
|
|
mEGLSurface = surface;
|
|
|
|
mEGL = egl;
|
|
|
|
mEGLConfig = config;
|
|
|
|
|
2016-12-07 00:25:09 +03:00
|
|
|
}
|
|
|
|
catch(Exception e)
|
|
|
|
{
|
2016-05-09 14:03:50 +00:00
|
|
|
Log.v(TAG, e + "");
|
2016-12-07 00:25:09 +03:00
|
|
|
for (StackTraceElement s : e.getStackTrace())
|
|
|
|
{
|
2016-05-09 14:03:50 +00:00
|
|
|
Log.v(TAG, s.toString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// EGL buffer flip
|
|
|
|
public void SwapBuffers()
|
|
|
|
{
|
|
|
|
if( mEGLSurface == null )
|
|
|
|
return;
|
|
|
|
mEGL.eglSwapBuffers(mEGLDisplay, mEGLSurface);
|
|
|
|
}
|
|
|
|
public void toggleEGL(int toggle)
|
|
|
|
{
|
|
|
|
if( toggle != 0 )
|
|
|
|
{
|
|
|
|
mEGLSurface = mEGL.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, this, null);
|
|
|
|
mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mEGL.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
|
|
|
|
mEGL.eglDestroySurface(mEGLDisplay, mEGLSurface);
|
|
|
|
mEGLSurface = null;
|
|
|
|
}
|
|
|
|
}
|
2016-08-05 19:17:03 +06:00
|
|
|
public void ShutdownGL()
|
|
|
|
{
|
|
|
|
mEGL.eglDestroyContext(mEGLDisplay, mEGLContext);
|
|
|
|
mEGLContext = null;
|
|
|
|
|
|
|
|
mEGL.eglDestroySurface(mEGLDisplay, mEGLSurface);
|
|
|
|
mEGLSurface = null;
|
|
|
|
|
|
|
|
mEGL.eglTerminate(mEGLDisplay);
|
|
|
|
mEGLDisplay = null;
|
|
|
|
}
|
2016-05-03 22:24:07 +00:00
|
|
|
|
|
|
|
|
2016-05-08 22:57:35 +00:00
|
|
|
@Override
|
2016-07-26 22:39:54 +06:00
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event)
|
|
|
|
{
|
2016-05-08 22:57:35 +00:00
|
|
|
return XashActivity.handleKey( keyCode, event );
|
|
|
|
}
|
2016-08-01 11:27:51 +00:00
|
|
|
|
2017-04-05 22:03:19 +00:00
|
|
|
@Override
|
|
|
|
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
|
|
|
Log.v(TAG, "PreIme: " + keyCode );
|
|
|
|
return super.dispatchKeyEvent(event);
|
|
|
|
}
|
|
|
|
|
2016-05-08 22:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This is a fake invisible editor view that receives the input and defines the
|
|
|
|
* pan&scan region
|
|
|
|
*/
|
|
|
|
class DummyEdit extends View implements View.OnKeyListener {
|
|
|
|
InputConnection ic;
|
|
|
|
|
|
|
|
public DummyEdit(Context context) {
|
|
|
|
super(context);
|
|
|
|
setFocusableInTouchMode(true);
|
|
|
|
setFocusable(true);
|
|
|
|
setOnKeyListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onCheckIsTextEditor() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
|
|
|
|
|
|
return XashActivity.handleKey( keyCode, event );
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
|
|
|
ic = new XashInputConnection(this, true);
|
|
|
|
|
|
|
|
outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
|
|
|
| 33554432 /* API 11: EditorInfo.IME_FLAG_NO_FULLSCREEN */;
|
|
|
|
|
|
|
|
return ic;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class XashInputConnection extends BaseInputConnection {
|
|
|
|
|
|
|
|
public XashInputConnection(View targetView, boolean fullEditor) {
|
|
|
|
super(targetView, fullEditor);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean sendKeyEvent(KeyEvent event) {
|
|
|
|
|
|
|
|
if( XashActivity.handleKey( event.getKeyCode(), event ) )
|
2016-05-05 20:01:43 +00:00
|
|
|
return true;
|
2016-05-08 22:57:35 +00:00
|
|
|
return super.sendKeyEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean commitText(CharSequence text, int newCursorPosition) {
|
|
|
|
|
|
|
|
//nativeCommitText(text.toString(), newCursorPosition);
|
2016-08-13 20:31:00 +00:00
|
|
|
if(text.toString().equals("\n"))
|
|
|
|
{
|
|
|
|
XashActivity.nativeKey(KeyEvent.KEYCODE_ENTER,1);
|
|
|
|
XashActivity.nativeKey(KeyEvent.KEYCODE_ENTER,0);
|
|
|
|
}
|
2016-05-08 22:57:35 +00:00
|
|
|
XashActivity.nativeString(text.toString());
|
|
|
|
|
|
|
|
return super.commitText(text, newCursorPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
|
|
|
|
|
|
|
//nativeSetComposingText(text.toString(), newCursorPosition);
|
|
|
|
XashActivity.nativeString(text.toString());
|
|
|
|
|
|
|
|
return super.setComposingText(text, newCursorPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
public native void nativeSetComposingText(String text, int newCursorPosition);
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
|
|
|
|
// Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
|
|
|
|
if (beforeLength == 1 && afterLength == 0) {
|
|
|
|
|
|
|
|
// backspace
|
|
|
|
XashActivity.nativeKey(1,KeyEvent.KEYCODE_DEL);
|
|
|
|
XashActivity.nativeKey(0,KeyEvent.KEYCODE_DEL);
|
2016-05-05 20:01:43 +00:00
|
|
|
}
|
2016-05-08 22:57:35 +00:00
|
|
|
|
|
|
|
return super.deleteSurroundingText(beforeLength, afterLength);
|
|
|
|
}
|
2016-05-06 08:58:01 +00:00
|
|
|
}
|
|
|
|
class EngineTouchListener_v1 implements View.OnTouchListener{
|
2016-05-09 14:03:50 +00:00
|
|
|
// Touch events
|
|
|
|
public boolean onTouch(View v, MotionEvent event)
|
|
|
|
{
|
|
|
|
XashActivity.nativeTouch(0, event.getAction(), event.getX(), event.getY());
|
2016-05-06 08:58:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2016-05-04 21:34:15 +00:00
|
|
|
|
2016-05-06 08:58:01 +00:00
|
|
|
class EngineTouchListener_v5 implements View.OnTouchListener{
|
2017-03-30 19:58:11 +00:00
|
|
|
float lx=0, ly=0;
|
|
|
|
boolean secondarypressed = false;
|
2016-05-09 14:03:50 +00:00
|
|
|
// Touch events
|
|
|
|
public boolean onTouch(View v, MotionEvent event)
|
|
|
|
{
|
|
|
|
final int touchDevId = event.getDeviceId();
|
|
|
|
final int pointerCount = event.getPointerCount();
|
|
|
|
int action = event.getActionMasked();
|
|
|
|
int pointerFingerId;
|
|
|
|
int mouseButton;
|
|
|
|
int i = -1;
|
|
|
|
float x,y;
|
2017-03-30 19:58:11 +00:00
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
switch(action) {
|
|
|
|
case MotionEvent.ACTION_MOVE:
|
2017-04-05 22:03:19 +00:00
|
|
|
if( (!XashActivity.fMouseShown) && ( (XashActivity.handler.getSource(event) & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ) )
|
2017-03-30 19:58:11 +00:00
|
|
|
{
|
|
|
|
x = event.getX();
|
|
|
|
y = event.getY();
|
|
|
|
|
|
|
|
XashActivity.nativeMouseMove(x - lx, y -ly);
|
|
|
|
lx = x;
|
|
|
|
ly = y;
|
2017-03-30 21:39:08 +00:00
|
|
|
return true;
|
2017-03-30 19:58:11 +00:00
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
for (i = 0; i < pointerCount; i++) {
|
|
|
|
pointerFingerId = event.getPointerId(i);
|
|
|
|
x = event.getX(i);
|
|
|
|
y = event.getY(i);
|
|
|
|
XashActivity.nativeTouch(pointerFingerId, 2, x, y);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MotionEvent.ACTION_UP:
|
|
|
|
case MotionEvent.ACTION_DOWN:
|
2017-04-05 22:03:19 +00:00
|
|
|
if( !XashActivity.fMouseShown && ( (XashActivity.handler.getSource(event) & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ) )
|
2017-03-30 19:58:11 +00:00
|
|
|
{
|
|
|
|
lx = event.getX();
|
|
|
|
ly = event.getY();
|
|
|
|
boolean down = action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN;
|
2017-03-30 23:32:27 +00:00
|
|
|
int buttonState = XashActivity.handler.getButtonState( event );
|
|
|
|
if( down && (buttonState & MotionEvent.BUTTON_SECONDARY) != 0 )
|
2017-03-30 19:58:11 +00:00
|
|
|
{
|
|
|
|
XashActivity.nativeKey( 1,-243 );
|
|
|
|
secondarypressed = true;
|
|
|
|
return true;
|
|
|
|
}
|
2017-03-30 23:32:27 +00:00
|
|
|
else if( !down && secondarypressed && (buttonState & MotionEvent.BUTTON_SECONDARY) == 0 )
|
2017-03-30 19:58:11 +00:00
|
|
|
{
|
|
|
|
secondarypressed = false;
|
|
|
|
XashActivity.nativeKey( 0,-243 );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
XashActivity.nativeKey( down?1:0,-241 );
|
|
|
|
return true;
|
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
i = 0;
|
2017-03-30 19:58:11 +00:00
|
|
|
|
2017-03-31 18:34:08 +00:00
|
|
|
case MotionEvent.ACTION_POINTER_UP:
|
|
|
|
case MotionEvent.ACTION_POINTER_DOWN:
|
|
|
|
|
2016-05-09 14:03:50 +00:00
|
|
|
// Non primary pointer up/down
|
|
|
|
if (i == -1) {
|
|
|
|
i = event.getActionIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
pointerFingerId = event.getPointerId(i);
|
|
|
|
|
|
|
|
x = event.getX(i);
|
|
|
|
y = event.getY(i);
|
|
|
|
if( action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP )
|
|
|
|
XashActivity.nativeTouch(pointerFingerId,1, x, y);
|
|
|
|
if( action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN )
|
|
|
|
XashActivity.nativeTouch(pointerFingerId,0, x, y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MotionEvent.ACTION_CANCEL:
|
|
|
|
for (i = 0; i < pointerCount; i++) {
|
|
|
|
pointerFingerId = event.getPointerId(i);
|
|
|
|
x = event.getX(i);
|
|
|
|
y = event.getY(i);
|
|
|
|
XashActivity.nativeTouch(pointerFingerId, 1, x, y);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-05-03 22:24:07 +00:00
|
|
|
return true;
|
2016-05-04 21:02:09 +00:00
|
|
|
}
|
2016-05-09 14:03:50 +00:00
|
|
|
}
|
2017-03-04 15:55:06 +03:00
|
|
|
|
2016-05-09 15:05:28 +00:00
|
|
|
class AndroidBug5497Workaround {
|
|
|
|
|
|
|
|
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
|
|
|
|
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
|
|
|
|
|
|
|
|
public static void assistActivity (Activity activity) {
|
|
|
|
new AndroidBug5497Workaround(activity);
|
|
|
|
}
|
|
|
|
|
|
|
|
private View mChildOfContent;
|
|
|
|
private int usableHeightPrevious;
|
|
|
|
private FrameLayout.LayoutParams frameLayoutParams;
|
|
|
|
|
|
|
|
private AndroidBug5497Workaround(Activity activity) {
|
|
|
|
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
|
|
|
|
mChildOfContent = content.getChildAt(0);
|
|
|
|
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
|
|
public void onGlobalLayout() {
|
|
|
|
possiblyResizeChildOfContent();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void possiblyResizeChildOfContent() {
|
|
|
|
int usableHeightNow = computeUsableHeight();
|
|
|
|
if (usableHeightNow != usableHeightPrevious) {
|
|
|
|
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
|
|
|
|
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
|
|
|
|
if (heightDifference > (usableHeightSansKeyboard/4)) {
|
|
|
|
// keyboard probably just became visible
|
|
|
|
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
|
2016-08-09 10:50:52 +00:00
|
|
|
XashActivity.keyboardVisible = true;
|
2016-05-09 15:05:28 +00:00
|
|
|
} else {
|
|
|
|
// keyboard probably just became hidden
|
|
|
|
frameLayoutParams.height = usableHeightSansKeyboard;
|
2016-08-09 10:50:52 +00:00
|
|
|
XashActivity.keyboardVisible = false;
|
2016-05-09 15:05:28 +00:00
|
|
|
}
|
2016-08-09 10:50:52 +00:00
|
|
|
if( XashActivity.mImmersiveMode != null )
|
|
|
|
XashActivity.mImmersiveMode.apply();
|
2016-05-09 15:05:28 +00:00
|
|
|
mChildOfContent.requestLayout();
|
|
|
|
usableHeightPrevious = usableHeightNow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private int computeUsableHeight() {
|
|
|
|
Rect r = new Rect();
|
|
|
|
mChildOfContent.getWindowVisibleDisplayFrame(r);
|
|
|
|
return (r.bottom - r.top);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2016-08-01 11:27:51 +00:00
|
|
|
|
2016-08-05 17:43:46 +00:00
|
|
|
class ImmersiveMode
|
|
|
|
{
|
|
|
|
void apply()
|
|
|
|
{
|
|
|
|
//stub
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ImmersiveMode_v19 extends ImmersiveMode
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
void apply()
|
|
|
|
{
|
2016-08-09 10:50:52 +00:00
|
|
|
if( !XashActivity.keyboardVisible )
|
|
|
|
XashActivity.mDecorView.setSystemUiVisibility(
|
2017-03-04 15:55:06 +03:00
|
|
|
0x00000100 // View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
2016-08-09 10:50:52 +00:00
|
|
|
| 0x00000200 // View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
|
|
| 0x00000400 // View.SYSTEM_UI_FLAG_LAYOUT_FULSCREEN
|
|
|
|
| 0x00000002 // View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
|
|
|
|
| 0x00000004 // View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
|
|
|
|
| 0x00001000 // View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
|
|
);
|
|
|
|
else
|
|
|
|
XashActivity.mDecorView.setSystemUiVisibility( 0 );
|
2016-08-05 17:43:46 +00:00
|
|
|
|
|
|
|
}
|
2016-08-09 10:50:52 +00:00
|
|
|
}
|
2017-03-26 22:11:27 +00:00
|
|
|
|
|
|
|
class JoystickHandler
|
|
|
|
{
|
|
|
|
public int getSource(KeyEvent event)
|
|
|
|
{
|
|
|
|
return InputDevice.SOURCE_UNKNOWN;
|
|
|
|
}
|
|
|
|
public int getSource(MotionEvent event)
|
|
|
|
{
|
|
|
|
return InputDevice.SOURCE_UNKNOWN;
|
|
|
|
}
|
|
|
|
public boolean handleAxis(MotionEvent event)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
public boolean isGamepadButton(int keyCode)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
public String keyCodeToString(int keyCode)
|
|
|
|
{
|
|
|
|
return String.valueOf(keyCode);
|
|
|
|
}
|
|
|
|
public void init()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
public boolean hasVibrator()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2017-03-30 00:25:51 +00:00
|
|
|
public void showMouse( boolean show )
|
|
|
|
{
|
|
|
|
}
|
2017-03-30 23:32:27 +00:00
|
|
|
public int getButtonState( MotionEvent event)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2017-03-30 00:25:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class Wrap_NVMouseExtensions{
|
|
|
|
private static Object inputManager;
|
|
|
|
private static Method mInputManager_setCursorVisibility;
|
2017-03-30 19:58:11 +00:00
|
|
|
public static int nMotionEvent_AXIS_RELATIVE_X = 0;
|
|
|
|
public static int nMotionEvent_AXIS_RELATIVE_Y = 0;
|
2017-03-30 00:25:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
|
|
static {
|
|
|
|
try { mInputManager_setCursorVisibility =
|
|
|
|
Class.forName("android.hardware.input.InputManager").getMethod("setCursorVisibility", boolean.class);
|
|
|
|
inputManager = XashActivity.mSingleton.getSystemService("input");
|
|
|
|
}
|
|
|
|
catch (Exception ex) { }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* DO THE SAME FOR RELATIVEY */
|
|
|
|
}
|
|
|
|
//**************************************************************************
|
|
|
|
public static void checkAvailable() throws Exception {
|
|
|
|
Field fieldMotionEvent_AXIS_RELATIVE_X = MotionEvent.class.getField("AXIS_RELATIVE_X");
|
|
|
|
nMotionEvent_AXIS_RELATIVE_X = (Integer)fieldMotionEvent_AXIS_RELATIVE_X.get(null);
|
|
|
|
Field fieldMotionEvent_AXIS_RELATIVE_Y = MotionEvent.class.getField("AXIS_RELATIVE_Y");
|
|
|
|
nMotionEvent_AXIS_RELATIVE_Y = (Integer)fieldMotionEvent_AXIS_RELATIVE_Y.get(null);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
|
|
public static void setCursorVisibility(boolean fVisibility) {
|
|
|
|
try { mInputManager_setCursorVisibility.invoke(inputManager, fVisibility); }
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
|
|
public static int getAxisRelativeX() { return nMotionEvent_AXIS_RELATIVE_X; };
|
|
|
|
public static int getAxisRelativeY() { return nMotionEvent_AXIS_RELATIVE_Y; };
|
2017-03-26 22:11:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class JoystickHandler_v12 extends JoystickHandler
|
|
|
|
{
|
|
|
|
private static float prevSide, prevFwd, prevYaw, prevPtch, prevLT, prevRT, prevHX, prevHY;
|
|
|
|
|
2017-03-30 00:25:51 +00:00
|
|
|
public static boolean mNVMouseExtensions = false;
|
|
|
|
|
|
|
|
static {
|
|
|
|
try { Wrap_NVMouseExtensions.checkAvailable();
|
|
|
|
mNVMouseExtensions = true;
|
|
|
|
}
|
|
|
|
catch (Throwable t) { mNVMouseExtensions = false; }
|
|
|
|
}
|
|
|
|
|
2017-03-26 22:11:27 +00:00
|
|
|
@Override
|
|
|
|
public void init()
|
|
|
|
{
|
|
|
|
XashActivity.mSurface.setOnGenericMotionListener(new MotionListener());
|
2017-03-30 00:25:51 +00:00
|
|
|
Log.d(XashActivity.TAG, "mNVMouseExtensions = " + mNVMouseExtensions );
|
2017-03-26 22:11:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getSource(KeyEvent event)
|
|
|
|
{
|
|
|
|
return event.getSource();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getSource(MotionEvent event)
|
|
|
|
{
|
|
|
|
return event.getSource();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean handleAxis( MotionEvent event )
|
|
|
|
{
|
|
|
|
// how event can be from null device, Android?
|
|
|
|
final InputDevice device = event.getDevice();
|
|
|
|
if( device == null )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// maybe I need to cache this...
|
|
|
|
for( InputDevice.MotionRange range: device.getMotionRanges() )
|
|
|
|
{
|
|
|
|
// normalize in -1.0..1.0 (copied from SDL2)
|
|
|
|
final float cur = ( event.getAxisValue( range.getAxis(), event.getActionIndex() ) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
|
|
|
|
final float dead = range.getFlat(); // get axis dead zone
|
|
|
|
switch( range.getAxis() )
|
|
|
|
{
|
|
|
|
// typical axes
|
|
|
|
// move
|
|
|
|
case MotionEvent.AXIS_X:
|
|
|
|
prevSide = XashActivity.performEngineAxisEvent(cur, XashActivity.JOY_AXIS_SIDE, prevSide, dead);
|
|
|
|
break;
|
|
|
|
case MotionEvent.AXIS_Y:
|
|
|
|
prevFwd = XashActivity.performEngineAxisEvent(cur, XashActivity.JOY_AXIS_FWD, prevFwd, dead);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// rotate. Invert, so by default this works as it's should
|
|
|
|
case MotionEvent.AXIS_Z:
|
|
|
|
prevPtch = XashActivity.performEngineAxisEvent(-cur, XashActivity.JOY_AXIS_PITCH, prevPtch, dead);
|
|
|
|
break;
|
|
|
|
case MotionEvent.AXIS_RZ:
|
|
|
|
prevYaw = XashActivity.performEngineAxisEvent(-cur, XashActivity.JOY_AXIS_YAW, prevYaw, dead);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// trigger
|
|
|
|
case MotionEvent.AXIS_RTRIGGER:
|
|
|
|
prevLT = XashActivity.performEngineAxisEvent(cur, XashActivity.JOY_AXIS_RT, prevLT, dead);
|
|
|
|
break;
|
|
|
|
case MotionEvent.AXIS_LTRIGGER:
|
|
|
|
prevRT = XashActivity.performEngineAxisEvent(cur, XashActivity.JOY_AXIS_LT, prevRT, dead);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// hats
|
|
|
|
case MotionEvent.AXIS_HAT_X:
|
|
|
|
prevHX = XashActivity.performEngineHatEvent(cur, true, prevHX);
|
|
|
|
break;
|
|
|
|
case MotionEvent.AXIS_HAT_Y:
|
|
|
|
prevHY = XashActivity.performEngineHatEvent(cur, false, prevHY);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isGamepadButton(int keyCode)
|
|
|
|
{
|
|
|
|
return KeyEvent.isGamepadButton(keyCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String keyCodeToString(int keyCode)
|
|
|
|
{
|
|
|
|
return KeyEvent.keyCodeToString(keyCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
class MotionListener implements View.OnGenericMotionListener
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
public boolean onGenericMotion(View view, MotionEvent event)
|
|
|
|
{
|
|
|
|
final int source = XashActivity.handler.getSource(event);
|
|
|
|
final int axisDevices = InputDevice.SOURCE_CLASS_JOYSTICK | InputDevice.SOURCE_GAMEPAD;
|
2017-03-30 19:58:11 +00:00
|
|
|
|
2017-04-05 22:03:19 +00:00
|
|
|
if( ( (source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ) && mNVMouseExtensions )
|
2017-03-30 00:25:51 +00:00
|
|
|
{
|
|
|
|
float x = event.getAxisValue(Wrap_NVMouseExtensions.getAxisRelativeX(), 0);
|
|
|
|
float y = event.getAxisValue(Wrap_NVMouseExtensions.getAxisRelativeY(), 0);
|
2017-03-30 19:58:11 +00:00
|
|
|
switch (event.getAction()) {
|
|
|
|
case MotionEvent.ACTION_SCROLL:
|
|
|
|
if (event.getAxisValue(MotionEvent.AXIS_VSCROLL) < 0.0f)
|
|
|
|
{
|
|
|
|
XashActivity.nativeKey(1,-239);
|
|
|
|
XashActivity.nativeKey(0,-239);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
XashActivity.nativeKey(1,-240);
|
|
|
|
XashActivity.nativeKey(0,-240);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2017-03-30 00:25:51 +00:00
|
|
|
|
|
|
|
XashActivity.nativeMouseMove( x, y );
|
|
|
|
Log.v("XashInput", "MouseMove: " +x + " " + y );
|
|
|
|
return true;
|
|
|
|
}
|
2017-03-30 19:58:11 +00:00
|
|
|
|
|
|
|
if( (source & axisDevices) != 0 )
|
|
|
|
return XashActivity.handler.handleAxis( event );
|
|
|
|
|
2017-03-26 22:11:27 +00:00
|
|
|
// TODO: Add it someday
|
|
|
|
// else if( (event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == InputDevice.SOURCE_CLASS_TRACKBALL )
|
|
|
|
// return XashActivity.handleBall( event );
|
|
|
|
//return super.onGenericMotion( view, event );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public boolean hasVibrator()
|
|
|
|
{
|
|
|
|
return XashActivity.mVibrator.hasVibrator();
|
|
|
|
}
|
2017-03-30 00:25:51 +00:00
|
|
|
public void showMouse( boolean show )
|
|
|
|
{
|
|
|
|
if( mNVMouseExtensions )
|
|
|
|
Wrap_NVMouseExtensions.setCursorVisibility( show );
|
|
|
|
}
|
2017-03-26 22:11:27 +00:00
|
|
|
}
|
2017-03-30 23:32:27 +00:00
|
|
|
|
|
|
|
class JoystickHandler_v14 extends JoystickHandler_v12
|
|
|
|
{
|
|
|
|
public int getButtonState( MotionEvent event )
|
|
|
|
{
|
|
|
|
return event.getButtonState();
|
|
|
|
}
|
|
|
|
};
|