2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "LaunchPrivatePCH.h"
# include "ExceptionHandling.h"
2014-10-07 05:41:02 -04:00
# include "AndroidPlatformCrashContext.h"
2014-03-14 14:13:41 -04:00
# include "AndroidJNI.h"
2014-11-17 11:31:49 -05:00
# include "AndroidApplication.h"
2014-05-13 11:40:41 -04:00
# include <Android/asset_manager.h>
# include <Android/asset_manager_jni.h>
2014-03-14 14:13:41 -04:00
# define JNI_CURRENT_VERSION JNI_VERSION_1_6
JavaVM * GJavaVM ;
2014-07-21 16:20:58 -04:00
// Pointer to target widget for virtual keyboard contents
2014-09-18 19:55:06 -04:00
static IVirtualKeyboardEntry * VirtualKeyboardWidget = NULL ;
2014-07-21 16:20:58 -04:00
2014-04-23 18:59:23 -04:00
extern FString GFilePathBase ;
2015-02-27 17:57:54 -05:00
extern FString GExternalFilePath ;
2014-09-09 12:20:07 -04:00
extern FString GFontPathBase ;
2014-05-13 11:40:41 -04:00
extern bool GOBBinAPK ;
2014-04-23 18:59:23 -04:00
2015-01-27 18:30:20 -05:00
FOnActivityResult FJavaWrapper : : OnActivityResultDelegate ;
2014-03-14 14:13:41 -04:00
//////////////////////////////////////////////////////////////////////////
2014-12-10 13:54:08 -05:00
# if UE_BUILD_SHIPPING
// always clear any exceptions in SHipping
2014-12-11 15:29:56 -05:00
# define CHECK_JNI_RESULT(Id) if (Id == 0) { Env->ExceptionClear(); }
2014-12-10 13:54:08 -05:00
# else
2014-12-11 15:29:56 -05:00
# define CHECK_JNI_RESULT(Id) \
2014-12-10 13:54:08 -05:00
if ( Id = = 0 ) \
{ \
2014-12-11 15:29:56 -05:00
if ( bIsOptional ) { Env - > ExceptionClear ( ) ; } \
else { Env - > ExceptionDescribe ( ) ; checkf ( Id ! = 0 , TEXT ( " Failed to find " # Id ) ) ; } \
2014-12-10 13:54:08 -05:00
}
# endif
void FJavaWrapper : : FindClassesAndMethods ( JNIEnv * Env )
{
bool bIsOptional = false ;
GameActivityClassID = FindClass ( Env , " com/epicgames/ue4/GameActivity " , bIsOptional ) ;
AndroidThunkJava_ShowConsoleWindow = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_ShowConsoleWindow " , " (Ljava/lang/String;)V " , bIsOptional ) ;
AndroidThunkJava_ShowVirtualKeyboardInput = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_ShowVirtualKeyboardInput " , " (ILjava/lang/String;Ljava/lang/String;)V " , bIsOptional ) ;
AndroidThunkJava_LaunchURL = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_LaunchURL " , " (Ljava/lang/String;)V " , bIsOptional ) ;
AndroidThunkJava_GetAssetManager = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_GetAssetManager " , " ()Landroid/content/res/AssetManager; " , bIsOptional ) ;
AndroidThunkJava_Minimize = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_Minimize " , " ()V " , bIsOptional ) ;
AndroidThunkJava_ForceQuit = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_ForceQuit " , " ()V " , bIsOptional ) ;
AndroidThunkJava_GetFontDirectory = FindStaticMethod ( Env , GameActivityClassID , " AndroidThunkJava_GetFontDirectory " , " ()Ljava/lang/String; " , bIsOptional ) ;
2015-02-06 17:57:32 -05:00
AndroidThunkJava_Vibrate = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_Vibrate " , " (I)V " , bIsOptional ) ;
2014-12-10 13:54:08 -05:00
AndroidThunkJava_IsMusicActive = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_IsMusicActive " , " ()Z " , bIsOptional ) ;
AndroidThunkJava_KeepScreenOn = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_KeepScreenOn " , " (Z)V " , bIsOptional ) ;
AndroidThunkJava_InitHMDs = FindMethod ( Env , GameActivityClassID , " AndroidThunkJava_InitHMDs " , " ()V " , bIsOptional ) ;
// the rest are optional
bIsOptional = true ;
// @todo split GooglePlay
// GoogleServicesClassID = FindClass(Env, "com/epicgames/ue4/GoogleServices", bIsOptional);
GoogleServicesClassID = GameActivityClassID ;
AndroidThunkJava_ResetAchievements = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_ResetAchievements " , " ()V " , bIsOptional ) ;
AndroidThunkJava_ShowAdBanner = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_ShowAdBanner " , " (Ljava/lang/String;Z)V " , bIsOptional ) ;
AndroidThunkJava_HideAdBanner = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_HideAdBanner " , " ()V " , bIsOptional ) ;
AndroidThunkJava_CloseAdBanner = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_CloseAdBanner " , " ()V " , bIsOptional ) ;
// In app purchase functionality
AndroidThunkJava_IapSetupService = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_IapSetupService " , " (Ljava/lang/String;)V " , bIsOptional ) ;
AndroidThunkJava_IapQueryInAppPurchases = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_IapQueryInAppPurchases " , " ([Ljava/lang/String;[Z)Z " , bIsOptional ) ;
AndroidThunkJava_IapBeginPurchase = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_IapBeginPurchase " , " (Ljava/lang/String;Z)Z " , bIsOptional ) ;
AndroidThunkJava_IapIsAllowedToMakePurchases = FindMethod ( Env , GoogleServicesClassID , " AndroidThunkJava_IapIsAllowedToMakePurchases " , " ()Z " , bIsOptional ) ;
}
jclass FJavaWrapper : : FindClass ( JNIEnv * Env , const ANSICHAR * ClassName , bool bIsOptional )
{
jclass Class = Env - > FindClass ( ClassName ) ;
CHECK_JNI_RESULT ( Class ) ;
return Class ;
}
jmethodID FJavaWrapper : : FindMethod ( JNIEnv * Env , jclass Class , const ANSICHAR * MethodName , const ANSICHAR * MethodSignature , bool bIsOptional )
{
jmethodID Method = Class = = NULL ? NULL : Env - > GetMethodID ( Class , MethodName , MethodSignature ) ;
CHECK_JNI_RESULT ( Method ) ;
return Method ;
}
jmethodID FJavaWrapper : : FindStaticMethod ( JNIEnv * Env , jclass Class , const ANSICHAR * MethodName , const ANSICHAR * MethodSignature , bool bIsOptional )
{
jmethodID Method = Class = = NULL ? NULL : Env - > GetStaticMethodID ( Class , MethodName , MethodSignature ) ;
CHECK_JNI_RESULT ( Method ) ;
return Method ;
}
jfieldID FJavaWrapper : : FindField ( JNIEnv * Env , jclass Class , const ANSICHAR * FieldName , const ANSICHAR * FieldType , bool bIsOptional )
{
jfieldID Field = Class = = NULL ? NULL : Env - > GetFieldID ( Class , FieldName , FieldType ) ;
CHECK_JNI_RESULT ( Field ) ;
return Field ;
}
void FJavaWrapper : : CallVoidMethod ( JNIEnv * Env , jobject Object , jmethodID Method , . . . )
{
// make sure the function exists
if ( Method = = NULL | | Object = = NULL )
{
return ;
}
va_list Args ;
va_start ( Args , Method ) ;
2015-01-05 08:44:51 -05:00
Env - > CallVoidMethodV ( Object , Method , Args ) ;
2014-12-10 13:54:08 -05:00
va_end ( Args ) ;
}
jobject FJavaWrapper : : CallObjectMethod ( JNIEnv * Env , jobject Object , jmethodID Method , . . . )
{
if ( Method = = NULL | | Object = = NULL )
{
return NULL ;
}
va_list Args ;
va_start ( Args , Method ) ;
2015-01-05 08:44:51 -05:00
jobject Return = Env - > CallObjectMethodV ( Object , Method , Args ) ;
2014-12-10 13:54:08 -05:00
va_end ( Args ) ;
return Return ;
}
bool FJavaWrapper : : CallBooleanMethod ( JNIEnv * Env , jobject Object , jmethodID Method , . . . )
{
if ( Method = = NULL | | Object = = NULL )
{
return false ;
}
va_list Args ;
va_start ( Args , Method ) ;
2015-01-05 08:44:51 -05:00
jboolean Return = Env - > CallBooleanMethodV ( Object , Method , Args ) ;
2014-12-10 13:54:08 -05:00
va_end ( Args ) ;
return ( bool ) Return ;
}
2014-03-14 14:13:41 -04:00
//Declare all the static members of the class defs
2014-12-10 13:54:08 -05:00
jclass FJavaWrapper : : GameActivityClassID ;
jobject FJavaWrapper : : GameActivityThis ;
jmethodID FJavaWrapper : : AndroidThunkJava_ShowConsoleWindow ;
jmethodID FJavaWrapper : : AndroidThunkJava_ShowVirtualKeyboardInput ;
jmethodID FJavaWrapper : : AndroidThunkJava_LaunchURL ;
jmethodID FJavaWrapper : : AndroidThunkJava_GetAssetManager ;
jmethodID FJavaWrapper : : AndroidThunkJava_Minimize ;
jmethodID FJavaWrapper : : AndroidThunkJava_ForceQuit ;
jmethodID FJavaWrapper : : AndroidThunkJava_GetFontDirectory ;
jmethodID FJavaWrapper : : AndroidThunkJava_Vibrate ;
jmethodID FJavaWrapper : : AndroidThunkJava_IsMusicActive ;
jmethodID FJavaWrapper : : AndroidThunkJava_KeepScreenOn ;
jmethodID FJavaWrapper : : AndroidThunkJava_InitHMDs ;
jclass FJavaWrapper : : GoogleServicesClassID ;
jobject FJavaWrapper : : GoogleServicesThis ;
jmethodID FJavaWrapper : : AndroidThunkJava_ResetAchievements ;
jmethodID FJavaWrapper : : AndroidThunkJava_ShowAdBanner ;
jmethodID FJavaWrapper : : AndroidThunkJava_HideAdBanner ;
jmethodID FJavaWrapper : : AndroidThunkJava_CloseAdBanner ;
jmethodID FJavaWrapper : : AndroidThunkJava_IapSetupService ;
jmethodID FJavaWrapper : : AndroidThunkJava_IapQueryInAppPurchases ;
jmethodID FJavaWrapper : : AndroidThunkJava_IapBeginPurchase ;
jmethodID FJavaWrapper : : AndroidThunkJava_IapIsAllowedToMakePurchases ;
2014-03-14 14:13:41 -04:00
//Game-specific crash reporter
2014-10-01 14:45:04 -04:00
void EngineCrashHandler ( const FGenericCrashContext & GenericContext )
2014-03-14 14:13:41 -04:00
{
2014-12-10 13:54:08 -05:00
const FAndroidCrashContext & Context = static_cast < const FAndroidCrashContext & > ( GenericContext ) ;
2014-03-14 14:13:41 -04:00
static int32 bHasEntered = 0 ;
if ( FPlatformAtomics : : InterlockedCompareExchange ( & bHasEntered , 1 , 0 ) = = 0 )
{
const SIZE_T StackTraceSize = 65535 ;
ANSICHAR * StackTrace = ( ANSICHAR * ) FMemory : : Malloc ( StackTraceSize ) ;
StackTrace [ 0 ] = 0 ;
// Walk the stack and dump it to the allocated memory.
FPlatformStackWalk : : StackWalkAndDump ( StackTrace , StackTraceSize , 0 , Context . Context ) ;
UE_LOG ( LogEngine , Error , TEXT ( " %s " ) , ANSI_TO_TCHAR ( StackTrace ) ) ;
FMemory : : Free ( StackTrace ) ;
GError - > HandleError ( ) ;
FPlatformMisc : : RequestExit ( true ) ;
}
}
2014-09-18 17:09:29 -04:00
void AndroidThunkCpp_KeepScreenOn ( bool Enable )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-09-18 17:09:29 -04:00
{
// call the java side
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_KeepScreenOn , Enable ) ;
2014-09-18 17:09:29 -04:00
}
}
2015-02-06 17:57:32 -05:00
void AndroidThunkCpp_Vibrate ( int32 Duration )
2014-09-16 17:32:10 -04:00
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-09-16 17:32:10 -04:00
{
// call the java side
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_Vibrate , Duration ) ;
2014-09-16 17:32:10 -04:00
}
}
2014-10-20 19:15:50 -04:00
// Call the Java side code for initializing VR HMD modules
void AndroidThunkCpp_InitHMDs ( )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-10-20 19:15:50 -04:00
{
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_InitHMDs ) ;
2014-10-20 19:15:50 -04:00
}
}
2014-03-14 14:13:41 -04:00
void AndroidThunkCpp_ShowConsoleWindow ( )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-03-14 14:13:41 -04:00
{
// figure out all the possible texture formats that are allowed
TArray < FString > PossibleTargetPlatforms ;
FPlatformMisc : : GetValidTargetPlatforms ( PossibleTargetPlatforms ) ;
// separate the format suffixes with commas
FString ConsoleText ;
for ( int32 FormatIndex = 0 ; FormatIndex < PossibleTargetPlatforms . Num ( ) ; FormatIndex + + )
{
const FString & Format = PossibleTargetPlatforms [ FormatIndex ] ;
int32 UnderscoreIndex ;
if ( Format . FindLastChar ( ' _ ' , UnderscoreIndex ) )
{
if ( ConsoleText ! = TEXT ( " " ) )
{
ConsoleText + = " , " ;
}
2014-12-10 13:54:08 -05:00
ConsoleText + = Format . Mid ( UnderscoreIndex + 1 ) ;
2014-03-14 14:13:41 -04:00
}
}
// call the java side
2014-12-10 13:54:08 -05:00
jstring ConsoleTextJava = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * ConsoleText ) ) ;
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_ShowConsoleWindow , ConsoleTextJava ) ;
2014-03-14 14:13:41 -04:00
Env - > DeleteLocalRef ( ConsoleTextJava ) ;
}
}
2014-09-18 19:55:06 -04:00
void AndroidThunkCpp_ShowVirtualKeyboardInput ( TSharedPtr < IVirtualKeyboardEntry > TextWidget , int32 InputType , const FString & Label , const FString & Contents )
2014-07-21 16:20:58 -04:00
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-07-21 16:20:58 -04:00
{
// remember target widget for contents
VirtualKeyboardWidget = & ( * TextWidget ) ;
// call the java side
jstring LabelJava = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * Label ) ) ;
jstring ContentsJava = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * Contents ) ) ;
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_ShowVirtualKeyboardInput , InputType , LabelJava , ContentsJava ) ;
2014-07-21 16:20:58 -04:00
Env - > DeleteLocalRef ( ContentsJava ) ;
Env - > DeleteLocalRef ( LabelJava ) ;
}
}
//This function is declared in the Java-defined class, GameActivity.java: "public native void nativeVirtualKeyboardResult(bool update, String contents);"
extern " C " void Java_com_epicgames_ue4_GameActivity_nativeVirtualKeyboardResult ( JNIEnv * jenv , jobject thiz , jboolean update , jstring contents )
{
// update text widget with new contents if OK pressed
if ( update = = JNI_TRUE )
{
if ( VirtualKeyboardWidget ! = NULL )
{
const char * javaChars = jenv - > GetStringUTFChars ( contents , 0 ) ;
2014-09-18 19:55:06 -04:00
VirtualKeyboardWidget - > SetTextFromVirtualKeyboard ( FText : : FromString ( FString ( UTF8_TO_TCHAR ( javaChars ) ) ) ) ;
2014-07-21 16:20:58 -04:00
//Release the string
jenv - > ReleaseStringUTFChars ( contents , javaChars ) ;
}
}
// release reference
VirtualKeyboardWidget = NULL ;
}
2014-03-14 14:13:41 -04:00
void AndroidThunkCpp_LaunchURL ( const FString & URL )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-03-14 14:13:41 -04:00
{
jstring Argument = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * URL ) ) ;
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_LaunchURL , Argument ) ;
2014-03-14 14:13:41 -04:00
Env - > DeleteLocalRef ( Argument ) ;
}
}
2014-07-28 12:50:02 -04:00
void AndroidThunkCpp_ResetAchievements ( )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-07-28 12:50:02 -04:00
{
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_ResetAchievements ) ;
2014-07-28 12:50:02 -04:00
}
}
2014-04-28 12:19:40 -04:00
void AndroidThunkCpp_ShowAdBanner ( const FString & AdUnitID , bool bShowOnBottomOfScreen )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-04-28 12:19:40 -04:00
{
jstring AdUnitIDArg = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * AdUnitID ) ) ;
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_ShowAdBanner , AdUnitIDArg , bShowOnBottomOfScreen ) ;
2014-04-28 12:19:40 -04:00
Env - > DeleteLocalRef ( AdUnitIDArg ) ;
2014-12-10 13:54:08 -05:00
}
2014-04-28 12:19:40 -04:00
}
void AndroidThunkCpp_HideAdBanner ( )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-04-28 12:19:40 -04:00
{
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_HideAdBanner ) ;
2014-04-28 12:19:40 -04:00
}
}
void AndroidThunkCpp_CloseAdBanner ( )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-04-28 12:19:40 -04:00
{
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_CloseAdBanner ) ;
2014-04-28 12:19:40 -04:00
}
}
2014-05-13 11:40:41 -04:00
namespace
{
jobject GJavaAssetManager = NULL ;
AAssetManager * GAssetManagerRef = NULL ;
}
2014-11-17 11:31:49 -05:00
jobject AndroidJNI_GetJavaAssetManager ( )
{
if ( ! GJavaAssetManager )
{
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
{
2014-12-10 13:54:08 -05:00
GJavaAssetManager = FJavaWrapper : : CallObjectMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_GetAssetManager ) ;
2014-11-17 11:31:49 -05:00
Env - > NewGlobalRef ( GJavaAssetManager ) ;
}
}
return GJavaAssetManager ;
}
2014-05-13 11:40:41 -04:00
AAssetManager * AndroidThunkCpp_GetAssetManager ( )
{
if ( ! GAssetManagerRef )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-05-13 11:40:41 -04:00
{
2014-11-17 11:31:49 -05:00
jobject JavaAssetMgr = AndroidJNI_GetJavaAssetManager ( ) ;
GAssetManagerRef = AAssetManager_fromJava ( Env , JavaAssetMgr ) ;
2014-05-13 11:40:41 -04:00
}
}
return GAssetManagerRef ;
}
2014-08-04 20:46:25 -04:00
void AndroidThunkCpp_Minimize ( )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-08-04 20:46:25 -04:00
{
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_Minimize ) ;
2014-08-04 20:46:25 -04:00
}
}
void AndroidThunkCpp_ForceQuit ( )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-08-04 20:46:25 -04:00
{
2014-12-10 13:54:08 -05:00
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_ForceQuit ) ;
2014-08-04 20:46:25 -04:00
}
}
2014-09-12 11:37:24 -04:00
bool AndroidThunkCpp_IsMusicActive ( )
{
2014-12-10 13:54:08 -05:00
bool bIsActive = false ;
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-09-12 11:37:24 -04:00
{
2014-12-10 13:54:08 -05:00
bIsActive = FJavaWrapper : : CallBooleanMethod ( Env , FJavaWrapper : : GameActivityThis , FJavaWrapper : : AndroidThunkJava_IsMusicActive ) ;
2014-09-12 11:37:24 -04:00
}
2014-12-10 13:54:08 -05:00
return bIsActive ;
2014-09-12 11:37:24 -04:00
}
2014-10-30 17:06:50 -04:00
void AndroidThunkCpp_Iap_SetupIapService ( const FString & InProductKey )
{
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-10-30 17:06:50 -04:00
{
2014-12-10 13:54:08 -05:00
jstring ProductKey = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * InProductKey ) ) ;
FJavaWrapper : : CallVoidMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_IapSetupService , ProductKey ) ;
Env - > DeleteLocalRef ( ProductKey ) ;
2014-10-30 17:06:50 -04:00
}
}
bool AndroidThunkCpp_Iap_QueryInAppPurchases ( const TArray < FString > & ProductIDs , const TArray < bool > & bConsumable )
{
FPlatformMisc : : LowLevelOutputDebugString ( L " [JNI] - AndroidThunkCpp_Iap_QueryInAppPurchases " ) ;
bool bResult = false ;
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-10-30 17:06:50 -04:00
{
2014-12-10 13:54:08 -05:00
static jclass StringClass = Env - > FindClass ( " java/lang/String " ) ;
// Populate some java types with the provided product information
jobjectArray ProductIDArray = ( jobjectArray ) Env - > NewObjectArray ( ProductIDs . Num ( ) , StringClass , NULL ) ;
jbooleanArray ConsumeArray = ( jbooleanArray ) Env - > NewBooleanArray ( ProductIDs . Num ( ) ) ;
jboolean * ConsumeArrayValues = Env - > GetBooleanArrayElements ( ConsumeArray , 0 ) ;
for ( uint32 Param = 0 ; Param < ProductIDs . Num ( ) ; Param + + )
2014-10-30 17:06:50 -04:00
{
2014-12-10 13:54:08 -05:00
jstring StringValue = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * ProductIDs [ Param ] ) ) ;
Env - > SetObjectArrayElement ( ProductIDArray , Param , StringValue ) ;
Env - > DeleteLocalRef ( StringValue ) ;
2014-10-30 17:06:50 -04:00
2014-12-10 13:54:08 -05:00
ConsumeArrayValues [ Param ] = bConsumable [ Param ] ;
2014-10-30 17:06:50 -04:00
}
2014-12-10 13:54:08 -05:00
Env - > ReleaseBooleanArrayElements ( ConsumeArray , ConsumeArrayValues , 0 ) ;
// Execute the java code for this operation
bResult = FJavaWrapper : : CallBooleanMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_IapQueryInAppPurchases , ProductIDArray , ConsumeArray ) ;
// clean up references
Env - > DeleteLocalRef ( ProductIDArray ) ;
Env - > DeleteLocalRef ( ConsumeArray ) ;
2014-10-30 17:06:50 -04:00
}
return bResult ;
}
bool AndroidThunkCpp_Iap_BeginPurchase ( const FString & ProductID , const bool bConsumable )
{
FPlatformMisc : : LowLevelOutputDebugString ( L " [JNI] - AndroidThunkCpp_Iap_BeginPurchase " ) ;
bool bResult = false ;
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-10-30 17:06:50 -04:00
{
2014-12-10 13:54:08 -05:00
jstring ProductIdJava = Env - > NewStringUTF ( TCHAR_TO_UTF8 ( * ProductID ) ) ;
bResult = FJavaWrapper : : CallBooleanMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_IapBeginPurchase , ProductIdJava , bConsumable ) ;
Env - > DeleteLocalRef ( ProductIdJava ) ;
2014-10-30 17:06:50 -04:00
}
return bResult ;
}
bool AndroidThunkCpp_Iap_IsAllowedToMakePurchases ( )
{
FPlatformMisc : : LowLevelOutputDebugString ( L " [JNI] - AndroidThunkCpp_Iap_IsAllowedToMakePurchases " ) ;
bool bResult = false ;
2014-11-17 11:31:49 -05:00
if ( JNIEnv * Env = FAndroidApplication : : GetJavaEnv ( ) )
2014-10-30 17:06:50 -04:00
{
2014-12-10 13:54:08 -05:00
bResult = FJavaWrapper : : CallBooleanMethod ( Env , FJavaWrapper : : GoogleServicesThis , FJavaWrapper : : AndroidThunkJava_IapIsAllowedToMakePurchases ) ;
2014-10-30 17:06:50 -04:00
}
return bResult ;
}
2014-03-14 14:13:41 -04:00
//The JNI_OnLoad function is triggered by loading the game library from
//the Java source file.
// static
// {
// System.loadLibrary("MyGame");
// }
//
// Use the JNI_OnLoad function to map all the class IDs and method IDs to their respective
// variables. That way, later when the Java functions need to be called, the IDs will be ready.
// It is much slower to keep looking up the class and method IDs.
2014-08-04 20:46:25 -04:00
2014-03-14 14:13:41 -04:00
JNIEXPORT jint JNI_OnLoad ( JavaVM * InJavaVM , void * InReserved )
{
FPlatformMisc : : LowLevelOutputDebugString ( L " In the JNI_OnLoad function " ) ;
2014-12-10 13:54:08 -05:00
JNIEnv * Env = NULL ;
InJavaVM - > GetEnv ( ( void * * ) & Env , JNI_CURRENT_VERSION ) ;
2014-03-14 14:13:41 -04:00
2014-08-04 20:46:25 -04:00
// if you have problems with stuff being missing esspecially in distribution builds then it could be because proguard is stripping things from java
// check proguard-project.txt and see if your stuff is included in the exceptions
2014-03-14 14:13:41 -04:00
GJavaVM = InJavaVM ;
2014-12-10 13:54:08 -05:00
FAndroidApplication : : InitializeJavaEnv ( GJavaVM , JNI_CURRENT_VERSION , FJavaWrapper : : GameActivityThis ) ;
2014-03-14 14:13:41 -04:00
2014-12-10 13:54:08 -05:00
FJavaWrapper : : FindClassesAndMethods ( Env ) ;
2014-10-30 17:06:50 -04:00
2014-03-14 14:13:41 -04:00
// hook signals
# if UE_BUILD_DEBUG
2014-12-10 13:54:08 -05:00
if ( GAlwaysReportCrash )
2014-03-14 14:13:41 -04:00
# else
2014-12-10 13:54:08 -05:00
if ( 0 ) //!FPlatformMisc::IsDebuggerPresent() || GAlwaysReportCrash)
2014-03-14 14:13:41 -04:00
# endif
{
2014-11-14 21:25:15 -05:00
// disable crash handler.. getting better stack traces from system logcat for now
// FPlatformMisc::SetCrashHandler(EngineCrashHandler);
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:59:23 -04:00
// Cache path to external storage
2014-12-10 13:54:08 -05:00
jclass EnvClass = Env - > FindClass ( " android/os/Environment " ) ;
jmethodID getExternalStorageDir = Env - > GetStaticMethodID ( EnvClass , " getExternalStorageDirectory " , " ()Ljava/io/File; " ) ;
jobject externalStoragePath = Env - > CallStaticObjectMethod ( EnvClass , getExternalStorageDir , nullptr ) ;
jmethodID getFilePath = Env - > GetMethodID ( Env - > FindClass ( " java/io/File " ) , " getPath " , " ()Ljava/lang/String; " ) ;
jstring pathString = ( jstring ) Env - > CallObjectMethod ( externalStoragePath , getFilePath , nullptr ) ;
const char * nativePathString = Env - > GetStringUTFChars ( pathString , 0 ) ;
2014-04-23 18:59:23 -04:00
// Copy that somewhere safe
GFilePathBase = FString ( nativePathString ) ;
2014-12-10 13:54:08 -05:00
2014-04-23 18:59:23 -04:00
// then release...
2014-12-10 13:54:08 -05:00
Env - > ReleaseStringUTFChars ( pathString , nativePathString ) ;
2014-04-23 18:59:23 -04:00
FPlatformMisc : : LowLevelOutputDebugStringf ( TEXT ( " Path found as '%s' \n " ) , * GFilePathBase ) ;
2014-09-09 12:20:07 -04:00
// Get the system font directory
2014-12-10 13:54:08 -05:00
jstring fontPath = ( jstring ) Env - > CallStaticObjectMethod ( FJavaWrapper : : GameActivityClassID , FJavaWrapper : : AndroidThunkJava_GetFontDirectory ) ;
const char * nativeFontPathString = Env - > GetStringUTFChars ( fontPath , 0 ) ;
2014-09-09 12:20:07 -04:00
GFontPathBase = FString ( nativeFontPathString ) ;
2014-12-10 13:54:08 -05:00
Env - > ReleaseStringUTFChars ( fontPath , nativeFontPathString ) ;
2014-09-09 12:20:07 -04:00
FPlatformMisc : : LowLevelOutputDebugStringf ( TEXT ( " Font Path found as '%s' \n " ) , * GFontPathBase ) ;
2014-03-14 14:13:41 -04:00
// Wire up to core delegates, so core code can call out to Java
DECLARE_DELEGATE_OneParam ( FAndroidLaunchURLDelegate , const FString & ) ;
extern CORE_API FAndroidLaunchURLDelegate OnAndroidLaunchURL ;
OnAndroidLaunchURL = FAndroidLaunchURLDelegate : : CreateStatic ( & AndroidThunkCpp_LaunchURL ) ;
2014-08-04 20:46:25 -04:00
FPlatformMisc : : LowLevelOutputDebugString ( L " In the JNI_OnLoad function 5 " ) ;
2014-03-14 14:13:41 -04:00
return JNI_CURRENT_VERSION ;
}
//Native-defined functions
//This function is declared in the Java-defined class, GameActivity.java: "public native void nativeSetGlobalActivity();"
2014-12-10 13:54:08 -05:00
extern " C " void Java_com_epicgames_ue4_GameActivity_nativeSetGlobalActivity ( JNIEnv * jenv , jobject thiz /*, jobject googleServices*/ )
2014-03-14 14:13:41 -04:00
{
2014-12-10 13:54:08 -05:00
if ( ! FJavaWrapper : : GameActivityThis )
2014-03-14 14:13:41 -04:00
{
2014-12-10 13:54:08 -05:00
FJavaWrapper : : GameActivityThis = jenv - > NewGlobalRef ( thiz ) ;
FAndroidApplication : : InitializeJavaEnv ( GJavaVM , JNI_CURRENT_VERSION , FJavaWrapper : : GameActivityThis ) ;
if ( ! FJavaWrapper : : GameActivityThis )
2014-03-14 14:13:41 -04:00
{
FPlatformMisc : : LowLevelOutputDebugString ( L " Error setting the global GameActivity activity " ) ;
check ( false ) ;
}
2014-12-10 13:54:08 -05:00
// @todo split GooglePlay, this needs to be passed in to this function
FJavaWrapper : : GoogleServicesThis = FJavaWrapper : : GameActivityThis ;
// FJavaWrapper::GoogleServicesThis = jenv->NewGlobalRef(googleServices);
2015-01-27 13:05:32 -05:00
2015-01-29 16:01:25 -05:00
bool bIsOptional = false ;
FJavaWrapper : : GameActivityClassID = FJavaWrapper : : FindClass ( jenv , " com/epicgames/ue4/GameActivity " , bIsOptional ) ;
2015-01-27 13:05:32 -05:00
// Next we check to see if the OBB file is in the APK
jmethodID isOBBInAPKMethod = jenv - > GetStaticMethodID ( FJavaWrapper : : GameActivityClassID , " isOBBInAPK " , " ()Z " ) ;
GOBBinAPK = ( bool ) jenv - > CallStaticBooleanMethod ( FJavaWrapper : : GameActivityClassID , isOBBInAPKMethod , nullptr ) ;
2015-02-27 17:57:54 -05:00
// Cache path to external files directory
jclass ContextClass = jenv - > FindClass ( " android/content/Context " ) ;
jmethodID getExternalFilesDir = jenv - > GetMethodID ( ContextClass , " getExternalFilesDir " , " (Ljava/lang/String;)Ljava/io/File; " ) ;
jobject externalFilesDirPath = jenv - > CallObjectMethod ( FJavaWrapper : : GameActivityThis , getExternalFilesDir , nullptr ) ;
jmethodID getFilePath = jenv - > GetMethodID ( jenv - > FindClass ( " java/io/File " ) , " getPath " , " ()Ljava/lang/String; " ) ;
jstring externalFilesPathString = ( jstring ) jenv - > CallObjectMethod ( externalFilesDirPath , getFilePath , nullptr ) ;
const char * nativeExternalFilesPathString = jenv - > GetStringUTFChars ( externalFilesPathString , 0 ) ;
// Copy that somewhere safe
GExternalFilePath = FString ( nativeExternalFilesPathString ) ;
// then release...
jenv - > ReleaseStringUTFChars ( externalFilesPathString , nativeExternalFilesPathString ) ;
FPlatformMisc : : LowLevelOutputDebugStringf ( TEXT ( " ExternalFilePath found as '%s' \n " ) , * GExternalFilePath ) ;
2014-03-14 14:13:41 -04:00
}
}
extern " C " bool Java_com_epicgames_ue4_GameActivity_nativeIsShippingBuild ( JNIEnv * LocalJNIEnv , jobject LocalThiz )
{
# if UE_BUILD_SHIPPING
return JNI_TRUE ;
# else
return JNI_FALSE ;
# endif
}
2015-01-27 18:30:20 -05:00
extern " C " void Java_com_epicgames_ue4_GameActivity_nativeOnActivityResult ( JNIEnv * jenv , jobject thiz , jobject activity , jint requestCode , jint resultCode , jobject data )
{
FJavaWrapper : : OnActivityResultDelegate . Broadcast ( jenv , thiz , activity , requestCode , resultCode , data ) ;
}