Refactor XashActivity, fix crash in XashService, add compat wrappers

This commit is contained in:
mittorn 2020-07-07 07:28:43 +07:00
parent ac0e9b633d
commit 8602bd4e9e
5 changed files with 747 additions and 689 deletions

View file

@ -59,6 +59,12 @@ public class LauncherActivity extends Activity
} }
setContentView(R.layout.activity_launcher); setContentView(R.layout.activity_launcher);
if( sdk > 17 )
{
ImageView icon = (ImageView) findViewById(R.id.launcherIcon);
icon.setImageDrawable(getResources().getDrawable(R.mipmap.ic_launcher));
}
TabHost tabHost = (TabHost) findViewById(R.id.tabhost); TabHost tabHost = (TabHost) findViewById(R.id.tabhost);
@ -264,12 +270,11 @@ public class LauncherActivity extends Activity
hideRodirSettings( !useRoDir.isChecked() ); hideRodirSettings( !useRoDir.isChecked() );
updateResolutionResult(); updateResolutionResult();
toggleResolutionFields(); toggleResolutionFields();
FWGSLib.applyPermissions( this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, REQUEST_PERMISSIONS ); FWGSLib.cmp.applyPermissions( this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, REQUEST_PERMISSIONS );
if( !mPref.getBoolean("successfulRun",false) ) if( !mPref.getBoolean("successfulRun",false) )
showFirstRun(); showFirstRun();
} }
@Override
public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults ) public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults )
{ {
if( requestCode == REQUEST_PERMISSIONS ) if( requestCode == REQUEST_PERMISSIONS )
@ -434,6 +439,12 @@ public class LauncherActivity extends Activity
dialog.setContentView(R.layout.about); dialog.setContentView(R.layout.about);
dialog.setCancelable(true); dialog.setCancelable(true);
dialog.show(); dialog.show();
if( sdk > 17 )
{
ImageView icon = (ImageView) dialog.findViewById(R.id.aboutIcon);
icon.setImageDrawable(getResources().getDrawable(R.mipmap.ic_launcher));
}
TextView tView6 = (TextView) dialog.findViewById(R.id.textView6); TextView tView6 = (TextView) dialog.findViewById(R.id.textView6);
tView6.setMovementMethod(LinkMovementMethod.getInstance()); tView6.setMovementMethod(LinkMovementMethod.getInstance());
((Button)dialog.findViewById( R.id.button_about_ok )).setOnClickListener(new View.OnClickListener(){ ((Button)dialog.findViewById( R.id.button_about_ok )).setOnClickListener(new View.OnClickListener(){

View file

@ -32,7 +32,7 @@ import java.security.MessageDigest;
import su.xash.engine.R; import su.xash.engine.R;
import su.xash.engine.XashConfig; import su.xash.engine.XashConfig;
import su.xash.engine.JoystickHandler; import su.xash.engine.XashInput;
import android.provider.Settings.Secure; import android.provider.Settings.Secure;
import android.Manifest; import android.Manifest;
@ -57,8 +57,7 @@ public class XashActivity extends Activity {
public static final int sdk = Integer.valueOf( Build.VERSION.SDK ); public static final int sdk = Integer.valueOf( Build.VERSION.SDK );
public static final String TAG = "XASH3D:XashActivity"; public static final String TAG = "XASH3D:XashActivity";
public static int mPixelFormat; public static int mPixelFormat;
public static JoystickHandler handler; public static XashInput.JoystickHandler handler;
public static ImmersiveMode mImmersiveMode;
public static boolean keyboardVisible = false; public static boolean keyboardVisible = false;
public static boolean mEngineReady = false; public static boolean mEngineReady = false;
public static boolean mEnginePaused = false; public static boolean mEnginePaused = false;
@ -110,6 +109,7 @@ public class XashActivity extends Activity {
{ {
Log.v( TAG, "onCreate()" ); Log.v( TAG, "onCreate()" );
super.onCreate( savedInstanceState ); super.onCreate( savedInstanceState );
mEngineReady = false; mEngineReady = false;
if( sdk >= 8 && CertCheck.dumbAntiPDALifeCheck( this ) ) if( sdk >= 8 && CertCheck.dumbAntiPDALifeCheck( this ) )
@ -137,7 +137,7 @@ public class XashActivity extends Activity {
mUseRoDir = mPref.getBoolean("use_rodir", false); mUseRoDir = mPref.getBoolean("use_rodir", false);
mWriteDir = mPref.getString("writedir", FWGSLib.getExternalFilesDir( this )); mWriteDir = mPref.getString("writedir", FWGSLib.getExternalFilesDir( this ));
FWGSLib.applyPermissions( this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, REQUEST_PERMISSIONS ); FWGSLib.cmp.applyPermissions( this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, REQUEST_PERMISSIONS );
// just in case // just in case
if( mWriteDir.length() == 0 ) if( mWriteDir.length() == 0 )
@ -161,8 +161,7 @@ public class XashActivity extends Activity {
checkWritePermission( basedir ); checkWritePermission( basedir );
} }
} }
@Override
public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults ) public void onRequestPermissionsResult( int requestCode, String[] permissions, int[] grantResults )
{ {
if( requestCode == REQUEST_PERMISSIONS ) if( requestCode == REQUEST_PERMISSIONS )
@ -294,10 +293,7 @@ public class XashActivity extends Activity {
super.onWindowFocusChanged( hasFocus ); super.onWindowFocusChanged( hasFocus );
if( mImmersiveMode != null ) FWGSLib.cmp.applyImmersiveMode(keyboardVisible, mDecorView);
{
mImmersiveMode.apply();
}
} }
public static void setFolderAsk( Context ctx, Boolean b ) public static void setFolderAsk( Context ctx, Boolean b )
@ -430,14 +426,7 @@ public class XashActivity extends Activity {
SurfaceHolder holder = mSurface.getHolder(); SurfaceHolder holder = mSurface.getHolder();
holder.setType( SurfaceHolder.SURFACE_TYPE_GPU ); holder.setType( SurfaceHolder.SURFACE_TYPE_GPU );
handler = XashInput.getJoystickHandler();
if( sdk >= 14 )
handler = new JoystickHandler_v14();
else if( sdk >= 12 )
handler = new JoystickHandler_v12();
else
handler = new JoystickHandler();
handler.init();
mVibrator = ( Vibrator )getSystemService( Context.VIBRATOR_SERVICE ); mVibrator = ( Vibrator )getSystemService( Context.VIBRATOR_SERVICE );
mHasVibrator = handler.hasVibrator() && (mVibrator != null); mHasVibrator = handler.hasVibrator() && (mVibrator != null);
@ -446,14 +435,8 @@ public class XashActivity extends Activity {
mUseVolume = mPref.getBoolean( "usevolume", false ); mUseVolume = mPref.getBoolean( "usevolume", false );
if( mPref.getBoolean( "enableResizeWorkaround", true ) ) if( mPref.getBoolean( "enableResizeWorkaround", true ) )
AndroidBug5497Workaround.assistActivity( this ); AndroidBug5497Workaround.assistActivity( this );
if( XashActivity.mPref.getBoolean( "immersive_mode", false ) )
// Immersive Mode is available only at >KitKat mDecorView = getWindow().getDecorView();
Boolean enableImmersive = ( sdk >= 19 ) && ( mPref.getBoolean( "immersive_mode", true ) );
if( enableImmersive )
mImmersiveMode = new ImmersiveMode_v19();
else mImmersiveMode = new ImmersiveMode();
mDecorView = getWindow().getDecorView();
if( mPref.getBoolean( "resolution_fixed", false ) ) if( mPref.getBoolean( "resolution_fixed", false ) )
{ {
@ -480,11 +463,7 @@ public class XashActivity extends Activity {
} }
} }
} }
FWGSLib.cmp.startForegroundService( this, new Intent( getBaseContext(), XashService.class ) );
if( sdk >= Build.VERSION_CODES.O )
startForegroundService( new Intent( getBaseContext(), XashService.class ) );
else if( sdk >= 5 )
startService( new Intent( getBaseContext(), XashService.class ) );
mEngineReady = true; mEngineReady = true;
} }
@ -494,18 +473,7 @@ public class XashActivity extends Activity {
{ {
Intent intent = getIntent(); Intent intent = getIntent();
String enginedir; String enginedir = FWGSLib.cmp.getNativeLibDir(this);
try
{
ApplicationInfo ai = FWGSLib.getApplicationInfo(this, null, 0);
enginedir = ai.nativeLibraryDir;
}
catch(Exception e)
{
e.printStackTrace();
enginedir = getFilesDir().getParentFile().getPath() + "/lib";
}
String argv = FWGSLib.getStringExtraFromIntent( intent, "argv", mPref.getString( "argv", "-dev 3 -log" ) ); String argv = FWGSLib.getStringExtraFromIntent( intent, "argv", mPref.getString( "argv", "-dev 3 -log" ) );
String gamelibdir = FWGSLib.getStringExtraFromIntent( intent, "gamelibdir", enginedir ); String gamelibdir = FWGSLib.getStringExtraFromIntent( intent, "gamelibdir", enginedir );
@ -920,16 +888,14 @@ public class XashActivity extends Activity {
imm.showSoftInput( mTextEdit, 0 ); imm.showSoftInput( mTextEdit, 0 );
keyboardVisible = true; keyboardVisible = true;
if( XashActivity.mImmersiveMode != null ) FWGSLib.cmp.applyImmersiveMode( keyboardVisible, mDecorView );
XashActivity.mImmersiveMode.apply();
} }
else else
{ {
mTextEdit.setVisibility( View.GONE ); mTextEdit.setVisibility( View.GONE );
imm.hideSoftInputFromWindow( mTextEdit.getWindowToken(), 0 ); imm.hideSoftInputFromWindow( mTextEdit.getWindowToken(), 0 );
keyboardVisible = false; keyboardVisible = false;
if( XashActivity.mImmersiveMode != null ) FWGSLib.cmp.applyImmersiveMode( keyboardVisible, mDecorView );
XashActivity.mImmersiveMode.apply();
} }
} }
} }
@ -1050,18 +1016,6 @@ public class XashActivity extends Activity {
} }
} }
/**
Simple nativeInit() runnable
*/
class XashMain implements Runnable
{
public void run()
{
XashActivity.nativeInit( XashActivity.mArgv );
}
}
/** /**
EngineSurface. This is what we draw on, so we need to know when it's created EngineSurface. This is what we draw on, so we need to know when it's created
in order to do anything useful. in order to do anything useful.
@ -1096,10 +1050,7 @@ class EngineSurface extends SurfaceView implements SurfaceHolder.Callback, View.
setFocusableInTouchMode( true ); setFocusableInTouchMode( true );
requestFocus(); requestFocus();
setOnKeyListener( this ); setOnKeyListener( this );
if( XashActivity.sdk >= 5 ) setOnTouchListener( XashInput.getTouchListener() );
setOnTouchListener( new EngineTouchListener_v5() );
else
setOnTouchListener( new EngineTouchListener_v1() );
} }
// Called when we have a valid drawing surface // Called when we have a valid drawing surface
@ -1161,7 +1112,13 @@ class EngineSurface extends SurfaceView implements SurfaceHolder.Callback, View.
// Now start up the C app thread // Now start up the C app thread
if( mEngThread == null ) if( mEngThread == null )
{ {
mEngThread = new Thread( new XashMain(), "EngineThread" ); mEngThread = new Thread( new Runnable(){
@Override
public void run()
{
XashActivity.nativeInit( XashActivity.mArgv );
}
}, "EngineThread" );
mEngThread.start(); mEngThread.start();
} }
resizing = false; resizing = false;
@ -1381,214 +1338,6 @@ class EngineSurface extends SurfaceView implements SurfaceHolder.Callback, View.
} }
/* 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 ) )
return true;
return super.sendKeyEvent( event );
}
@Override
public boolean commitText( CharSequence text, int newCursorPosition )
{
// nativeCommitText(text.toString(), newCursorPosition);
if( text.toString().equals( "\n" ) )
{
XashActivity.nativeKey( 1, KeyEvent.KEYCODE_ENTER );
XashActivity.nativeKey( 0, KeyEvent.KEYCODE_ENTER );
}
XashActivity.nativeString( text.toString() );
return super.commitText( text, newCursorPosition );
}
@Override
public boolean setComposingText( CharSequence text, int newCursorPosition )
{
// a1batross:
// This method is intended to show composed text immediately
// that after will be replaced by text from "commitText" method
// Just leaving this unimplemented fixes "twice" input on T9/Swype-like keyboards
//ativeSetComposingText(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
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
if( beforeLength > 0 && afterLength == 0 )
{
boolean ret = true;
// backspace(s)
while( beforeLength-- > 0 )
{
boolean ret_key = sendKeyEvent( new KeyEvent( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ) )
&& sendKeyEvent( new KeyEvent( KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL ) );
ret = ret && ret_key;
}
return ret;
}
return super.deleteSurroundingText(beforeLength, afterLength);
}
}
class EngineTouchListener_v1 implements View.OnTouchListener
{
// Touch events
public boolean onTouch( View v, MotionEvent event )
{
XashActivity.nativeTouch( 0, event.getAction(), event.getX(), event.getY() );
return true;
}
}
class EngineTouchListener_v5 implements View.OnTouchListener
{
float lx = 0, ly = 0;
boolean secondarypressed = false;
// 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, mouseButton, i = -1;
float x, y;
switch( action )
{
case MotionEvent.ACTION_MOVE:
if( ( !XashActivity.fMouseShown ) && ( ( XashActivity.handler.getSource( event ) & InputDevice.SOURCE_MOUSE ) == InputDevice.SOURCE_MOUSE ) )
{
x = event.getX();
y = event.getY();
XashActivity.nativeMouseMove( x - lx, y - ly );
lx = x;
ly = y;
return true;
}
for( i = 0; i < pointerCount; i++ )
{
pointerFingerId = event.getPointerId( i );
x = event.getX( i ) * XashActivity.mTouchScaleX;
y = event.getY( i ) * XashActivity.mTouchScaleY;
XashActivity.nativeTouch( pointerFingerId, 2, x, y );
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_DOWN:
if( !XashActivity.fMouseShown && ( ( XashActivity.handler.getSource( event ) & InputDevice.SOURCE_MOUSE ) == InputDevice.SOURCE_MOUSE ) )
{
lx = event.getX();
ly = event.getY();
boolean down = ( action == MotionEvent.ACTION_DOWN ) || ( action == MotionEvent.ACTION_POINTER_DOWN );
int buttonState = XashActivity.handler.getButtonState( event );
if( down && ( buttonState & MotionEvent.BUTTON_SECONDARY ) != 0 )
{
XashActivity.nativeKey( 1, -243 );
secondarypressed = true;
return true;
}
else if( !down && secondarypressed && ( buttonState & MotionEvent.BUTTON_SECONDARY ) == 0 )
{
secondarypressed = false;
XashActivity.nativeKey( 0, -243 );
return true;
}
XashActivity.nativeKey( down ? 1 : 0, -241 );
return true;
}
i = 0;
// fallthrough
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN:
// Non primary pointer up/down
if( i == -1 )
{
i = event.getActionIndex();
}
pointerFingerId = event.getPointerId( i );
x = event.getX( i ) * XashActivity.mTouchScaleX;
y = event.getY( i ) * XashActivity.mTouchScaleY;
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 ) * XashActivity.mTouchScaleX;
y = event.getY( i ) * XashActivity.mTouchScaleY;
XashActivity.nativeTouch( pointerFingerId, 1, x, y );
}
break;
default: break;
}
return true;
}
}
class AndroidBug5497Workaround class AndroidBug5497Workaround
{ {
// For more information, see https://code.google.com/p/android/issues/detail?id=5497 // For more information, see https://code.google.com/p/android/issues/detail?id=5497
@ -1637,8 +1386,7 @@ class AndroidBug5497Workaround
XashActivity.keyboardVisible = false; XashActivity.keyboardVisible = false;
} }
if( XashActivity.mImmersiveMode != null ) FWGSLib.cmp.applyImmersiveMode( XashActivity.keyboardVisible, XashActivity.mDecorView );
XashActivity.mImmersiveMode.apply();
mChildOfContent.requestLayout(); mChildOfContent.requestLayout();
usableHeightPrevious = usableHeightNow; usableHeightPrevious = usableHeightNow;
@ -1651,377 +1399,4 @@ class AndroidBug5497Workaround
mChildOfContent.getWindowVisibleDisplayFrame( r ); mChildOfContent.getWindowVisibleDisplayFrame( r );
return r.bottom - r.top; return r.bottom - r.top;
} }
} }
class ImmersiveMode
{
void apply()
{
//stub
}
}
class ImmersiveMode_v19 extends ImmersiveMode
{
@Override
void apply()
{
if( !XashActivity.keyboardVisible )
XashActivity.mDecorView.setSystemUiVisibility(
0x00000100 // View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| 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 );
}
}
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;
}
public void showMouse( boolean show )
{
}
public int getButtonState( MotionEvent event )
{
return 0;
}
}
class Wrap_NVMouseExtensions
{
private static Object inputManager;
private static Method mInputManager_setCursorVisibility;
private static Method mView_setPointerIcon;
private static Class mPointerIcon;
private static Object mEmptyIcon;
public static int nMotionEvent_AXIS_RELATIVE_X = 0;
public static int nMotionEvent_AXIS_RELATIVE_Y = 0;
//**************************************************************************
static
{
try
{
mInputManager_setCursorVisibility =
Class.forName( "android.hardware.input.InputManager" ).getMethod( "setCursorVisibility", boolean.class );
inputManager = XashActivity.mSingleton.getSystemService( "input" );
}
catch( Exception ex )
{
try
{
mPointerIcon=Class.forName("android.view.PointerIcon");
mEmptyIcon = mPointerIcon.getDeclaredMethod("getSystemIcon",android.content.Context.class, int.class).invoke(null,XashActivity.mSingleton.getContext(),0);
mView_setPointerIcon = View.class.getMethod("setPointerIcon",mPointerIcon);
}
catch( Exception ex1 )
{
ex1.printStackTrace();
}
}
/* 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 );
}
static void setPointerIcon( View view, boolean fVisibility )
{
Log.v("XashInput", "SET CURSOR VISIBILITY " + fVisibility + " obj " + mEmptyIcon.toString() );
try
{
mView_setPointerIcon.invoke(view,fVisibility?null:mEmptyIcon);
}
catch( Exception e)
{
e.printStackTrace();
}
}
static void setGroupPointerIcon( ViewGroup parent, boolean fVisibility )
{
for( int i = parent.getChildCount() - 1; i >= 0; i-- )
{
try
{
final View child = parent.getChildAt(i);
if( child == null )
continue;
if( child instanceof ViewGroup )
{
setGroupPointerIcon((ViewGroup) child, fVisibility);
}
setPointerIcon( child, fVisibility);
}
catch( Exception ex )
{
ex.printStackTrace();
}
}
}
//**************************************************************************
public static void setCursorVisibility( boolean fVisibility )
{
try
{
mInputManager_setCursorVisibility.invoke( inputManager, fVisibility );
}
catch( Exception e )
{
try
{
ViewGroup rootViewGroup = (ViewGroup) XashActivity.mSingleton.getWindow().getDecorView();
setGroupPointerIcon(rootViewGroup, fVisibility);
setGroupPointerIcon((ViewGroup)XashActivity.mDecorView, fVisibility);
for (int i = 0; i < rootViewGroup.getChildCount(); i++) {
View view = rootViewGroup.getChildAt(i);
setPointerIcon(view, fVisibility);
}
}
catch( Exception ex)
{
ex.printStackTrace();
}
}
}
//**************************************************************************
public static int getAxisRelativeX()
{
return nMotionEvent_AXIS_RELATIVE_X;
}
public static int getAxisRelativeY()
{
return nMotionEvent_AXIS_RELATIVE_Y;
}
}
class JoystickHandler_v12 extends JoystickHandler
{
private static float prevSide, prevFwd, prevYaw, prevPtch, prevLT, prevRT, prevHX, prevHY;
public static boolean mNVMouseExtensions = false;
static int mouseId;
static
{
try
{
Wrap_NVMouseExtensions.checkAvailable();
mNVMouseExtensions = true;
}
catch( Throwable t )
{
mNVMouseExtensions = false;
}
}
@Override
public void init()
{
XashActivity.mSurface.setOnGenericMotionListener( new MotionListener() );
Log.d( XashActivity.TAG, "mNVMouseExtensions = " + mNVMouseExtensions );
}
@Override
public int getSource( KeyEvent event )
{
return event.getSource();
}
@Override
public int getSource( MotionEvent event )
{
if( event.getDeviceId() == mouseId )
return InputDevice.SOURCE_MOUSE;
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 );
if( FWGSLib.FExactBitSet( source, InputDevice.SOURCE_GAMEPAD ) ||
FWGSLib.FExactBitSet( source, InputDevice.SOURCE_CLASS_JOYSTICK ) )
return XashActivity.handler.handleAxis( event );
if( mNVMouseExtensions )
{
float x = event.getAxisValue( Wrap_NVMouseExtensions.getAxisRelativeX(), 0 );
float y = event.getAxisValue( Wrap_NVMouseExtensions.getAxisRelativeY(), 0 );
if( !FWGSLib.FExactBitSet( source, InputDevice.SOURCE_MOUSE) && (x != 0 || y != 0 ))
mouseId = event.getDeviceId();
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;
}
XashActivity.nativeMouseMove( x, y );
// Log.v("XashInput", "MouseMove: " +x + " " + y );
return true;
}
// 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;
}
}
@Override
public boolean hasVibrator()
{
if( XashActivity.mVibrator != null )
return XashActivity.mVibrator.hasVibrator();
return false;
}
@Override
public void showMouse( boolean show )
{
if( mNVMouseExtensions )
Wrap_NVMouseExtensions.setCursorVisibility( show );
}
}
class JoystickHandler_v14 extends JoystickHandler_v12
{
@Override
public int getButtonState( MotionEvent event )
{
return event.getButtonState();
}
}

View file

@ -0,0 +1,614 @@
package su.xash.engine;
import java.lang.*;
import java.lang.reflect.*;
import java.util.*;
import android.app.*;
import android.content.*;
import android.view.*;
import android.os.*;
import android.util.*;
import android.graphics.*;
import android.text.method.*;
import android.text.*;
import android.media.*;
import android.hardware.*;
import android.content.*;
import android.widget.*;
import android.content.pm.*;
import android.net.Uri;
import android.provider.*;
import android.view.inputmethod.*;
import su.xash.fwgslib.*;
public class XashInput
{
public static JoystickHandler getJoystickHandler()
{
JoystickHandler handler;
if( FWGSLib.sdk >= 14 )
handler = new JoystickHandler_v14();
else if( FWGSLib.sdk >= 12 )
handler = new JoystickHandler_v12();
else
handler = new JoystickHandler();
handler.init();
return handler;
}
public static 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;
}
public void showMouse( boolean show )
{
}
public int getButtonState( MotionEvent event )
{
return 0;
}
}
static class JoystickHandler_v12 extends JoystickHandler
{
private static float prevSide, prevFwd, prevYaw, prevPtch, prevLT, prevRT, prevHX, prevHY;
public static boolean mNVMouseExtensions = false;
static int mouseId;
static
{
try
{
Wrap_NVMouseExtensions.checkAvailable();
mNVMouseExtensions = true;
}
catch( Throwable t )
{
mNVMouseExtensions = false;
}
}
@Override
public void init()
{
XashActivity.mSurface.setOnGenericMotionListener( new MotionListener() );
Log.d( XashActivity.TAG, "mNVMouseExtensions = " + mNVMouseExtensions );
}
@Override
public int getSource( KeyEvent event )
{
return event.getSource();
}
@Override
public int getSource( MotionEvent event )
{
if( event.getDeviceId() == mouseId )
return InputDevice.SOURCE_MOUSE;
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 );
if( FWGSLib.FExactBitSet( source, InputDevice.SOURCE_GAMEPAD ) ||
FWGSLib.FExactBitSet( source, InputDevice.SOURCE_CLASS_JOYSTICK ) )
return XashActivity.handler.handleAxis( event );
if( mNVMouseExtensions )
{
float x = event.getAxisValue( Wrap_NVMouseExtensions.getAxisRelativeX(), 0 );
float y = event.getAxisValue( Wrap_NVMouseExtensions.getAxisRelativeY(), 0 );
if( !FWGSLib.FExactBitSet( source, InputDevice.SOURCE_MOUSE) && (x != 0 || y != 0 ))
mouseId = event.getDeviceId();
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;
}
XashActivity.nativeMouseMove( x, y );
// Log.v("XashInput", "MouseMove: " +x + " " + y );
return true;
}
// 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;
}
}
@Override
public boolean hasVibrator()
{
if( XashActivity.mVibrator != null )
return XashActivity.mVibrator.hasVibrator();
return false;
}
@Override
public void showMouse( boolean show )
{
if( mNVMouseExtensions )
Wrap_NVMouseExtensions.setCursorVisibility( show );
}
}
static class JoystickHandler_v14 extends JoystickHandler_v12
{
@Override
public int getButtonState( MotionEvent event )
{
return event.getButtonState();
}
}
public static View.OnTouchListener getTouchListener()
{
if( FWGSLib.sdk >= 5 )
return new EngineTouchListener_v5();
else
return new EngineTouchListener_v1();
}
}
class Wrap_NVMouseExtensions
{
private static Object inputManager;
private static Method mInputManager_setCursorVisibility;
private static Method mView_setPointerIcon;
private static Class mPointerIcon;
private static Object mEmptyIcon;
public static int nMotionEvent_AXIS_RELATIVE_X = 0;
public static int nMotionEvent_AXIS_RELATIVE_Y = 0;
//**************************************************************************
static
{
try
{
mInputManager_setCursorVisibility =
Class.forName( "android.hardware.input.InputManager" ).getMethod( "setCursorVisibility", boolean.class );
inputManager = XashActivity.mSingleton.getSystemService( "input" );
}
catch( Exception ex )
{
try
{
mPointerIcon=Class.forName("android.view.PointerIcon");
mEmptyIcon = mPointerIcon.getDeclaredMethod("getSystemIcon",android.content.Context.class, int.class).invoke(null,XashActivity.mSingleton.getContext(),0);
mView_setPointerIcon = View.class.getMethod("setPointerIcon",mPointerIcon);
}
catch( Exception ex1 )
{
ex1.printStackTrace();
}
}
/* 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 );
}
static void setPointerIcon( View view, boolean fVisibility )
{
Log.v("XashInput", "SET CURSOR VISIBILITY " + fVisibility + " obj " + mEmptyIcon.toString() );
try
{
mView_setPointerIcon.invoke(view,fVisibility?null:mEmptyIcon);
}
catch( Exception e)
{
e.printStackTrace();
}
}
static void setGroupPointerIcon( ViewGroup parent, boolean fVisibility )
{
for( int i = parent.getChildCount() - 1; i >= 0; i-- )
{
try
{
final View child = parent.getChildAt(i);
if( child == null )
continue;
if( child instanceof ViewGroup )
{
setGroupPointerIcon((ViewGroup) child, fVisibility);
}
setPointerIcon( child, fVisibility);
}
catch( Exception ex )
{
ex.printStackTrace();
}
}
}
//**************************************************************************
public static void setCursorVisibility( boolean fVisibility )
{
try
{
mInputManager_setCursorVisibility.invoke( inputManager, fVisibility );
}
catch( Exception e )
{
try
{
ViewGroup rootViewGroup = (ViewGroup) XashActivity.mSingleton.getWindow().getDecorView();
setGroupPointerIcon(rootViewGroup, fVisibility);
setGroupPointerIcon((ViewGroup)XashActivity.mDecorView, fVisibility);
for (int i = 0; i < rootViewGroup.getChildCount(); i++) {
View view = rootViewGroup.getChildAt(i);
setPointerIcon(view, fVisibility);
}
}
catch( Exception ex)
{
ex.printStackTrace();
}
}
}
//**************************************************************************
public static int getAxisRelativeX()
{
return nMotionEvent_AXIS_RELATIVE_X;
}
public static int getAxisRelativeY()
{
return nMotionEvent_AXIS_RELATIVE_Y;
}
}
class EngineTouchListener_v1 implements View.OnTouchListener
{
// Touch events
public boolean onTouch( View v, MotionEvent event )
{
XashActivity.nativeTouch( 0, event.getAction(), event.getX(), event.getY() );
return true;
}
}
class EngineTouchListener_v5 implements View.OnTouchListener
{
float lx = 0, ly = 0;
boolean secondarypressed = false;
// 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, mouseButton, i = -1;
float x, y;
switch( action )
{
case MotionEvent.ACTION_MOVE:
if( ( !XashActivity.fMouseShown ) && ( ( XashActivity.handler.getSource( event ) & InputDevice.SOURCE_MOUSE ) == InputDevice.SOURCE_MOUSE ) )
{
x = event.getX();
y = event.getY();
XashActivity.nativeMouseMove( x - lx, y - ly );
lx = x;
ly = y;
return true;
}
for( i = 0; i < pointerCount; i++ )
{
pointerFingerId = event.getPointerId( i );
x = event.getX( i ) * XashActivity.mTouchScaleX;
y = event.getY( i ) * XashActivity.mTouchScaleY;
XashActivity.nativeTouch( pointerFingerId, 2, x, y );
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_DOWN:
if( !XashActivity.fMouseShown && ( ( XashActivity.handler.getSource( event ) & InputDevice.SOURCE_MOUSE ) == InputDevice.SOURCE_MOUSE ) )
{
lx = event.getX();
ly = event.getY();
boolean down = ( action == MotionEvent.ACTION_DOWN ) || ( action == MotionEvent.ACTION_POINTER_DOWN );
int buttonState = XashActivity.handler.getButtonState( event );
if( down && ( buttonState & MotionEvent.BUTTON_SECONDARY ) != 0 )
{
XashActivity.nativeKey( 1, -243 );
secondarypressed = true;
return true;
}
else if( !down && secondarypressed && ( buttonState & MotionEvent.BUTTON_SECONDARY ) == 0 )
{
secondarypressed = false;
XashActivity.nativeKey( 0, -243 );
return true;
}
XashActivity.nativeKey( down ? 1 : 0, -241 );
return true;
}
i = 0;
// fallthrough
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN:
// Non primary pointer up/down
if( i == -1 )
{
i = event.getActionIndex();
}
pointerFingerId = event.getPointerId( i );
x = event.getX( i ) * XashActivity.mTouchScaleX;
y = event.getY( i ) * XashActivity.mTouchScaleY;
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 ) * XashActivity.mTouchScaleX;
y = event.getY( i ) * XashActivity.mTouchScaleY;
XashActivity.nativeTouch( pointerFingerId, 1, x, y );
}
break;
default: break;
}
return true;
}
}
/* 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 ) )
return true;
return super.sendKeyEvent( event );
}
@Override
public boolean commitText( CharSequence text, int newCursorPosition )
{
// nativeCommitText(text.toString(), newCursorPosition);
if( text.toString().equals( "\n" ) )
{
XashActivity.nativeKey( 1, KeyEvent.KEYCODE_ENTER );
XashActivity.nativeKey( 0, KeyEvent.KEYCODE_ENTER );
}
XashActivity.nativeString( text.toString() );
return super.commitText( text, newCursorPosition );
}
@Override
public boolean setComposingText( CharSequence text, int newCursorPosition )
{
// a1batross:
// This method is intended to show composed text immediately
// that after will be replaced by text from "commitText" method
// Just leaving this unimplemented fixes "twice" input on T9/Swype-like keyboards
//ativeSetComposingText(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
// and https://bugzilla.libsdl.org/show_bug.cgi?id=2265
if( beforeLength > 0 && afterLength == 0 )
{
boolean ret = true;
// backspace(s)
while( beforeLength-- > 0 )
{
boolean ret_key = sendKeyEvent( new KeyEvent( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ) )
&& sendKeyEvent( new KeyEvent( KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL ) );
ret = ret && ret_key;
}
return ret;
}
return super.deleteSurroundingText(beforeLength, afterLength);
}
}

View file

@ -32,7 +32,6 @@ import java.security.MessageDigest;
import su.xash.engine.R; import su.xash.engine.R;
import su.xash.engine.XashConfig; import su.xash.engine.XashConfig;
import su.xash.engine.JoystickHandler;
public class XashService extends Service public class XashService extends Service
@ -64,9 +63,9 @@ public class XashService extends Service
{ {
Log.d("XashService", "Service Started"); Log.d("XashService", "Service Started");
not = XashNotification.getXashNotification(this); not = XashNotification.getXashNotification();
startForeground(not.getId(), not.createNotification()); startForeground(not.getId(), not.createNotification(this));
return START_NOT_STICKY; return START_NOT_STICKY;
} }
@ -98,20 +97,16 @@ public class XashService extends Service
} }
stopSelf(); stopSelf();
} }
public static class XashNotification public static class XashNotification
{ {
public Notification notification; public Notification notification;
public final int notificationId = 100; public final int notificationId = 100;
public Context ctx; protected Context ctx;
public XashNotification(Context ctx)
{
this.ctx = ctx;
}
public Notification createNotification() public Notification createNotification(Context context)
{ {
ctx = context;
Intent engineIntent = new Intent(ctx, XashActivity.class); Intent engineIntent = new Intent(ctx, XashActivity.class);
engineIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); engineIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
@ -133,14 +128,14 @@ public class XashService extends Service
public void setIcon(Bitmap bmp) public void setIcon(Bitmap bmp)
{ {
notification.contentView.setImageViewBitmap( R.id.status_image, bmp ); notification.contentView.setImageViewBitmap( R.id.status_image, bmp );
NotificationManager nm = ctx.getSystemService(NotificationManager.class); NotificationManager nm = (NotificationManager)ctx.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify( notificationId, notification ); nm.notify( notificationId, notification );
} }
public void setText(String title) public void setText(String title)
{ {
notification.contentView.setTextViewText( R.id.status_text, title ); notification.contentView.setTextViewText( R.id.status_text, title );
NotificationManager nm = ctx.getSystemService(NotificationManager.class); NotificationManager nm = (NotificationManager)ctx.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify( notificationId, notification ); nm.notify( notificationId, notification );
} }
@ -149,28 +144,26 @@ public class XashService extends Service
return notificationId; return notificationId;
} }
public static XashNotification getXashNotification(Context ctx) public static XashNotification getXashNotification()
{ {
if( XashActivity.sdk >= Build.VERSION_CODES.O ) if( XashActivity.sdk >= 26 )
return new XashNotification_O(ctx); return new XashNotification_v26();
else if( XashActivity.sdk >= 21 ) // else if( XashActivity.sdk >= 21 )
return new XashNotification_v21(ctx); // return new XashNotification_v21();
return new XashNotification(ctx); else
return new XashNotification();
} }
} }
private static class XashNotification_v21 extends XashNotification private static class XashNotification_v21 extends XashNotification
{ {
protected Notification.Builder builder; protected Notification.Builder builder;
public XashNotification_v21(Context ctx)
{
super(ctx);
}
@Override @Override
public Notification createNotification() public Notification createNotification(Context context)
{ {
ctx = context;
Intent engineIntent = new Intent(ctx, XashActivity.class); Intent engineIntent = new Intent(ctx, XashActivity.class);
engineIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); engineIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
@ -196,7 +189,7 @@ public class XashService extends Service
public void setIcon(Bitmap bmp) public void setIcon(Bitmap bmp)
{ {
notification = builder.setLargeIcon(bmp).build(); notification = builder.setLargeIcon(bmp).build();
NotificationManager nm = ctx.getSystemService(NotificationManager.class); NotificationManager nm = (NotificationManager)ctx.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify( notificationId, notification ); nm.notify( notificationId, notification );
} }
@ -204,25 +197,21 @@ public class XashService extends Service
public void setText(String str) public void setText(String str)
{ {
notification = builder.setContentText(str).build(); notification = builder.setContentText(str).build();
NotificationManager nm = ctx.getSystemService(NotificationManager.class); NotificationManager nm = (NotificationManager)ctx.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify( notificationId, notification ); nm.notify( notificationId, notification );
} }
} }
private static class XashNotification_O extends XashNotification_v21
private static class XashNotification_v26 extends XashNotification_v21
{ {
private static final String CHANNEL_ID = "XashServiceChannel"; private static final String CHANNEL_ID = "XashServiceChannel";
public XashNotification_O(Context ctx)
{
super(ctx);
}
private void createNotificationChannel() private void createNotificationChannel()
{ {
// Create the NotificationChannel, but only on API 26+ because // Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library // the NotificationChannel class is new and not in the support library
if (XashActivity.sdk >= Build.VERSION_CODES.O) if (XashActivity.sdk >= 26)
{ {
final NotificationManager nm = ctx.getSystemService(NotificationManager.class); final NotificationManager nm = ctx.getSystemService(NotificationManager.class);
@ -244,14 +233,14 @@ public class XashService extends Service
} }
@Override @Override
public Notification createNotification() public Notification createNotification(Context ctx)
{ {
createNotificationChannel(); createNotificationChannel();
builder = new Notification.Builder(ctx); builder = new Notification.Builder(ctx);
builder.setChannelId(CHANNEL_ID); builder.setChannelId(CHANNEL_ID);
return super.createNotification(); return super.createNotification(ctx);
} }
} }
}; };

View file

@ -229,9 +229,58 @@ public class FWGSLib
} }
} }
public static void applyPermissions( final Activity act, final String permissions[], final int code ) public static class Compat
{ {
if( sdk >= 23 ) public void applyPermissions( final Activity act, final String permissions[], final int code ) {}
public void applyImmersiveMode( boolean keyboardVisible, View decorView ) {}
public void startForegroundService( Context ctx, Intent intent ) {}
public String getNativeLibDir(Context ctx)
{
return ctx.getFilesDir().getParentFile().getPath() + "/lib";
}
}
static class Compat_9 extends Compat
{
public String getNativeLibDir(Context ctx)
{
try {
ApplicationInfo ai = getApplicationInfo(ctx, null, 0);
return ai.nativeLibraryDir;
}
catch(Exception e) {
return super.getNativeLibDir(ctx);
}
}
public void startForegroundService( Context ctx, Intent intent ) {
ctx.startService( intent );
}
}
static class Compat_19 extends Compat_9
{
public void applyImmersiveMode(boolean keyboardVisible, View decorView)
{
//if( !XashActivity.mPref.getBoolean( "immersive_mode", false ) )
// return;
if( keyboardVisible )
decorView.setSystemUiVisibility(
0x00000100 // View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| 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
decorView.setSystemUiVisibility( 0 );
}
}
static class Compat_23 extends Compat_19
{
public void applyPermissions( final Activity act, final String permissions[], final int code )
{ {
List<String> requestPermissions = new ArrayList<String>(); List<String> requestPermissions = new ArrayList<String>();
@ -256,6 +305,25 @@ public class FWGSLib
} }
} }
static class Compat_26 extends Compat_23
{
public void startForegroundService(Context ctx, Intent intent){
ctx.startForegroundService(intent);
}
}
public static Compat cmp;
static {
int sdk1 = Integer.valueOf(Build.VERSION.SDK);
if( sdk1 >= 26 )
cmp = new Compat_26();
if( sdk1 >= 23 )
cmp = new Compat_23();
else if( sdk1 >= 9 )
cmp = new Compat_9();
else cmp = new Compat();
}
public static ApplicationInfo getApplicationInfo(Context ctx, String pkgName, int flags) throws PackageManager.NameNotFoundException public static ApplicationInfo getApplicationInfo(Context ctx, String pkgName, int flags) throws PackageManager.NameNotFoundException
{ {
PackageManager pm = ctx.getPackageManager(); PackageManager pm = ctx.getPackageManager();
@ -268,3 +336,4 @@ public class FWGSLib
public static final int sdk = Integer.valueOf(Build.VERSION.SDK); public static final int sdk = Integer.valueOf(Build.VERSION.SDK);
} }