You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rb none #lockdown nick.penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 3292215 on 2017/02/08 by Nick.Shin HTML5 emscripten: wasm and wbegl2 support - emscripten toolchain #jira UEPLAT-1437 Switch [to] web assembly #rb none Change 3293994 on 2017/02/09 by Nick.Shin HTML5 emscripten: wasm and webgl2 support - OSX toolchain #jira UEPLAT-1437 Switch [to] web assembly #rb none Change 3317951 on 2017/02/22 by Nick.Shin HTML5 emscripten: wasm & webgl2 support - RC1 - emscripten toolchain WARNING: emscripten/incoming/source/include/libc/bit (the file) might need to be deleted first #jira UEMOB-263 Switch [to] web assembly #jira UEMOB-201 Support ES3 / WebGL2 in HTML5 #rb none Change 3318669 on 2017/02/23 by Nick.Shin HTML5 emscripten: wasm & webgl2 support - RC1 - OSX toolchain #jira UEMOB-263 Switch [to] web assembly #jira UEMOB-201 Support ES3 / WebGL2 in HTML5 #rb none Change 3462146 on 2017/05/26 by Nick.Shin HTML5 - merge from Release-4.16 to Dev-Mobile #jira none #rb none #rnx Change 3504996 on 2017/06/22 by Cosmin.Sulea UEMOB-362 - Add per-texture and per-format compression quality override settings #rb Dmitriy.Dyomin #jira UEMOB-362 #codereview Dmitriy.Dyomin #codereview Jack.Porter Change 3505056 on 2017/06/22 by Cosmin.Sulea Back out changelist 3504996 - due to errors generated in xboxOne, PS4 and Switch versions #rb none Change 3508049 on 2017/06/23 by Nick.Shin HTML5 toolchain notes corrections #jira none #rb none #rnx Change 3508663 on 2017/06/24 by Nick.Shin HTML5LaunchHelper.exe on linux - redo - it seems that i need to also check-in the exe and pdb file instead of having CIS make and checking-in them itself... - modified c# program to output a version number to help track which version of HTML5LaunchHelper is running... #jira UE-45302 HTML5LaunchHelper.exe hosts the files in the current working directory on Linux #rnx #rb none Change 3509210 on 2017/06/26 by Dmitriy.Dyomin ExposureScale will be applied during tonemap pass when MobileHDR is on #rb jack.porter #codereview Allan.Bentham Change 3511058 on 2017/06/27 by Cosmin.Sulea UEMOB-362 - Add per-texture and per-format compression quality override settings - resubmitted #rb Dmitriy.Dyomin #jira UEMOB-362 #codereview Dmitriy.Dyomin Change 3511069 on 2017/06/27 by Jack.Porter PS4, XboxOne and Switch fixes for changes to ITextureFormat interface #rb Dmitriy.Dyomin #jira UEMOB-362 Change 3513028 on 2017/06/28 by Jack.Porter Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile) #rb None Change 3517409 on 2017/06/30 by Jack.Porter Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile) #rb None Change 3517730 on 2017/06/30 by Cosmin.Sulea UEMOB-328 - Improve handling of iOS signing key on remote Mac system keychain when using remote toolchain #rb Jack.Porter #jira UEMOB-328 #codereview: peter.sauerbrei Change 3517757 on 2017/06/30 by Cosmin.Sulea UE-46245 - Building with remote toolchain does not use Project Setting for iOS signing identity which can cause signing errors #rb Jack.Porter #jira UE-46245 #codereview: peter.sauerbrei Change 3518149 on 2017/06/30 by Adrian.Chelu UE-43035 Tilt axis for X and Z are not consistent between Android and iOS devices #rb Jack.Porter #jira UE-46245 #codereview: Chris Babcock <chris.babcock@epicgames.com> Change 3524242 on 2017/07/06 by Nick.Shin HTML5 - refraction shader note: this CL also contains fixes to webgl2 [float4 vs half2] and a [% vs Mod()] material custom function changes to some TM-ShaderModels shaders specifically: fixes to and similar with: DitherTemporalAA #jria UE-46434 No Refraction in QA Game TM-Shadermodels HTML5 #rb none #rn #codereview jack.porter dmitriy.dyomin Change 3535295 on 2017/07/13 by Allan.Bentham #jira UEMOB-390 Add Android cpu stats. add 'stat AndroidCPU' to android's console spinner UI. increase GetCPUState's core count support to 16. #jira UE-45888 Use cvar value to limit android cpu stat update rate. #rb none Change 3535306 on 2017/07/13 by Allan.Bentham Add missing pragma once #rb none Change 3537047 on 2017/07/13 by Ben.Marsh Fixing case of iOS directories, pt1 #rb none Change 3537051 on 2017/07/13 by Ben.Marsh Fixing case of iOS directories, pt2 #rb none Change 3537373 on 2017/07/14 by Allan.Bentham Add scope level android egl error verification. work around minor issue with invalid egl config property. #rb chris.babcock Change3541735on 2017/07/18 by Allan.Bentham Add 'sustained performance mode' support for API 24+ devices. #jira UEMOB-386 #rb chris.babcock Change 3543001 on 2017/07/18 by Sorin.Gradinaru #jira UE-45766 Improved Virtual Keyboard cannot receive non-English characters. - for Android, add an native EditBox above the virtual keyboard to receive the text and pass it to the object from the slate #rb Chris.Babcock Change 3554399 on 2017/07/25 by Nick.Shin STATS disabled for non multi-threaded platforms #jira UE-47485 ( Pri:1 - 4.18 ) Crash running Stat Command test in TM-Core on Firefox #rnx #rb none Change 3554402 on 2017/07/25 by Nick.Shin STATS TaskGraph disabled for non multi-threaded platforms #jira UE-47486 ( Pri:1 - 4.18 ) QAGame hard locks on Firefox when triggering Task Graph Benchmark test #rb none #rnx Change 3556957 on 2017/07/26 by Nick.Shin HTML5 - WASM enabled by default - part 1 -- commenting out asmjs stuff begin sunsetting ASM.JS note to self: CL#3462146 "backout" asmjs #jira UEMOB-416 WASM enabled by default #rnx #rb none Change 3557654 on 2017/07/26 by Nick.Shin HTML5 - WASM enabled by default - part 2 -- remove asmjs code sunsetting ASM.JS note to self: CL#3462146 "backout" asmjs #jira UEMOB-416 WASM enabled by default #rn #rb none Change 3557910 on 2017/07/27 by Jack.Porter Support Client configuration when packaging in the editor #jira UE-39973 #rb Dmitriy.Dyomin Change3557917on 2017/07/27 by Jack.Porter Missing file from CL 3557910 #rb trivial Change 3559642 on 2017/07/27 by Nick.Shin STATS TaskGraph disabled for non multi-threaded platforms - both "LockFree stress test" and "task graph benchmark" are disabled - no multi-threading for WASM exist yet (note: ASM.JS has been sunsetted) - stat command crash "fixed" - but, font size are totally broken - i can look at this (much) later... - new bug: physx will crash on "gc and level load stress test" -- please bug this as a new jira #jira UE-47486 ( Pri:1 - 4.18 ) QAGame hard locks on Firefox when triggering Task Graph Benchmark test #rb none #rnx Change 3565656 on 2017/07/31 by Dmitriy.Dyomin Added a way to lock level position in Word Composition #jira UE-47713 #rb none Change 3565757 on 2017/08/01 by Dmitriy.Dyomin compile fix #rb none Change 3567446 on 2017/08/01 by Chris.Babcock Allow addElement and addElements to only insert once with once="true" attribute in UPL #jira UE-47951 #ue4 #android #rb Peter.Sauerbrei Change 3567592 on 2017/08/01 by Chris.Babcock Use absolute path for repositories for Gradle #jira UE-47952 #ue4 #android #rb Tim.Lincoln Change 3568690 on 2017/08/02 by Chris.Babcock Removed warnings for once attribute in UPL #ue4 #android #rb none Change 3569975 on 2017/08/02 by Chris.Babcock Add <baseBuildGradleAdditions> to UPL to allow additions to the root-level build.gradle #jira UE-47995 #ue4 #android #rb Tim.Lincoln Change 3570117 on 2017/08/02 by Chris.Babcock Add <setBoolFromPropertyContains> to UPL - sets bool to true if string list in ini matches contains attribute #jira UE-47996 #ue4 #android #rb Jack.Porter Change 3571552 on 2017/08/03 by Chris.Babcock Removed unneeded settings.gradle file (generated) #jira UE-48041 #ue4 #android #rb none Change 3572224 on 2017/08/04 by Dmitriy.Dyomin Better selection tracking in world composition #rb none Change 3573662 on 2017/08/04 by Nick.Shin HTML5 remove PreLoadMap "feature" (was only available/used with HTML5) - asyncronous loads are not allowed during UEngine::LoadMap() - the files/code will be repurposed for pakfile CHUNK support #jira UEMOB-425 HTML5 streaming content investigation (part 1 of 2) #rn #rb none Change 3574471 on 2017/08/07 by Dmitriy.Dyomin Export ULevelStreamingKismet::LoadLevelInstance function #rb none Change 3576262 on 2017/08/08 by Dmitriy.Dyomin Fixed: widget clipping issues in world composition #rb none Change 3576845 on 2017/08/08 by Nick.Shin set HTML5LaunchHelper application's icon to UE4.ico #jira UE-19225 HTML5LaunchHelper application does not have an unreal icon #rb none #rnx Change 3578313 on 2017/08/09 by Dmitriy.Dyomin Added: an RHI call to invalidate/clear cached state, RHIInvalidateCachedState #jira UEMOB-435 #rb jack.porter Change 3578364 on 2017/08/09 by Dmitriy.Dyomin Vertex Fog is disabled on mobile by default. If scene uses vertex fog - Mobile preview and device will show on screen message: PROJECT HAS VERTEX FOG ON MOBILE DISABLED This saves about 90 instructions in VS and a few in PS #jira UEMOB-166 #rb jack.porter Change 3578703 on 2017/08/09 by Nick.Shin set HTML5LaunchHelper application's icon to UE4.ico forgot to check in exe and pdb file #jira UE-19225 HTML5LaunchHelper application does not have an unreal icon #rb none #rnx Change 3578961 on 2017/08/09 by Peter.Sauerbrei deprecate IOS 8 as the minimum OS supported. #jira UEMOB-429 #rb chris.babcock Change 3579319 on 2017/08/09 by Peter.Sauerbrei fixes for compile errors with Xcode 9 beta 4 #rb none Change 3579356 on 2017/08/09 by Peter.Sauerbrei modified minimum IOS to build with #rb chris.babcock Change 3579687 on 2017/08/09 by Chris.Babcock Fix GoogleVR Gradle packaging #jira UE-48239 #ue4 #android #rb none Change 3579921 on 2017/08/10 by Dmitriy.Dyomin GitHub 3670 : More zoom levels for World Composition (300) #contributedby: user37337 #jira UE-45977 #3670 #rb none Change 3580576 on 2017/08/10 by Peter.Sauerbrei detection of iPad Pro 10.5 and IPad Pro 12.9 (2nd Gen) #rb chris.babcock Change 3580611 on 2017/08/10 by Chris.Babcock Set online provider back to GooglePlay and remove forcing IAP permission (contributed by umerov1999) #jira UE-48185 #PR #3876 #ue4 #android #rb Peter.Sauerbrei Change 3582166 on 2017/08/11 by Nick.Shin nuke PLATFORM_HTML5_WIN32 PLATFORM_HTML5_WIN32 code removal tested successfully with (force rebuild and repackaging): * Win64 server (WindowsServer) * Win64 client (WindowsNoEditor) * HTML5 client all playing together via websocket net driver (i've attached a screen shot of this in jira) code changes touches: physics, audio and main build files #jira UEMOB-433 Remove Win32 SDL "HTML5 Simulator" code #rb ben.marsh #rnx #codereview josh.adams #fyi ori.cohen, aaron.mclera Change 3582474 on 2017/08/11 by Chris.Babcock Don't use V2 signing for Gear VR APKs #jira UE-48354 #ue4 #android #rb Peter.Sauerbrei Change 3582614 on 2017/08/11 by Chris.Babcock Filter out unneeded architectures from APK for Gradle builds #jira UE-48355 #ue4 #android #rb Peter.Sauerbrei Change 3582923 on 2017/08/11 by Nick.Shin backport release 4.17 to dev-mobile #jira none #rb none #rnx Change 3582924 on 2017/08/11 by Nick.Shin FNetworkFileServerHttp - error gracefully when port is already in use #jira UE-46409 [CrashReport] Assertion on Mac: Could not create a libwebsocket - FNetworkFileServerHttp::Init() #rnx #rb none Change 3582925 on 2017/08/11 by Nick.Shin HTML5 - turn off pak file compression in favor of gzip packages #jira UE-46729 HTML5 - on shipping builds - turn off pak file compression in favor of gzip packages #rn #rb none Change 3583943 on 2017/08/14 by Cosmin.Sulea UEMOB-363 - second iteration - Project wide texture quality control by texture group #rb Dmitriy Dyomin #jira UEMOB-363 Change 3583967 on 2017/08/14 by Cosmin.Sulea Back out changelist 3583943 #rb none Change 3584121 on 2017/08/14 by Peter.Sauerbrei fix for mac compile failure #rb none Change 3587877 on 2017/08/15 by Peter.Sauerbrei josh's suggested fix is not working for Xcode 8.3, so brute forcing for now #rb none Change 3588612 on 2017/08/15 by Peter.Sauerbrei Xcode 9 project compatbility updates #rb chris.babcock #codereview michael.trepka Change 3589223 on 2017/08/15 by Dmitriy.Dyomin Fixed: bNavigationAutoUpdateEnabled was not always working when reopeinig the map Fixed: Navigation Build was not clearing some mesh tiles when bNavigationAutoUpdateEnabled is enabled Fixed: Streaming out a level in editor was not always updating NavMesh debug draw #rb lukasz.furman Change 3589900 on 2017/08/16 by Dmitriy.Dyomin Support vulkan validation layers on Android, only in Debug and Development configuration (requires r.Vulkan.EnableValidation=1) #codereview chris.babcock, rolando.caloca #rb none Change 3590592 on 2017/08/16 by Nick.Shin HTML5 emscripten 1.37.19 OSX #jira UE-47813 #rb none #rn HTML5 emscripten 1.37.19 OSX Change 3590597 on 2017/08/16 by Nick.Shin HTML5 emscripten 1.37.19 Linux #jira UE-47813 #rb none #rn HTML5 emscripten 1.37.19 Linux Change 3590624 on 2017/08/16 by Nick.Shin HTML5 emscripten 1.37.19 toolchain #jira UE-47813 #rb none #rn HTML5 emscripten 1.37.19 toolchain Change 3591720 on 2017/08/16 by Chris.Babcock Enable Gradle by default and add button to accept Android SDK license to project settings #jira UE-48519 #ue4 #android #rb Tim.Lincoln #fyi Peter.Sauerbrei Change 3591998 on 2017/08/16 by Chris.Babcock Fix nonunity build #ue4 #android #rb none Change 3592407 on 2017/08/17 by Nick.Shin HTML5 emscripten 1.37.19 Win64 #jira UE-47813 #rb none #rn HTML5 emscripten 1.37.19 Win64 Change 3592479 on 2017/08/17 by Nick.Shin HTML5 3rd Party Libs - compiled with emscripten 1.37.19 #jira UE-47813 #rb none #rn HTML5 3rd Party Libs - compiled with emscripten 1.37.19 toolchain Change 3592480 on 2017/08/17 by Nick.Shin HTML5 emscripten 1.37.19 toolchain Epic edits as well as setting UE4 HTML c# scripts to use new toolchain #jira UE-47813 #rb none #rn HTML5 emscripten 1.37.19 toolchain Epic edits Change 3592481 on 2017/08/17 by Nick.Shin HTML5 remove old emscripten toolchain #jira UE-47813 #rb none #rn HTML5 remove old emscripten toolchain Change 3592485 on 2017/08/17 by Nick.Shin HTML5 undo CanUseXGE - this might be breaking CIS for HTML5 builds... #jira UE-47813 #rb none #rnx Change 3592549 on 2017/08/17 by Dmitriy.Dyomin Added GetDiskTotalAndFreeSpace for IOS and Android #jira UE-46479 #codereview chris.babcock, peter.sauerbrei #rb none Change 3594045 on 2017/08/17 by Peter.Sauerbrei comment about potential failure case in the remote tool chain #rb none Change 3594342 on 2017/08/17 by Peter.Sauerbrei Merging //UE4/Main/... to //UE4/Dev-Mobile/... #rb none Change 3594920 on 2017/08/17 by Peter.Sauerbrei fix for non-unity builds (accidentally merged something incorrectly) #rb none Change 3595347 on 2017/08/17 by Chris.Babcock merge fixes for Android #ue4 #android #rb Peter.Sauerbrei #lockdown Peter.Sauerbrei Change 3595752 on 2017/08/17 by Chris.Babcock Update Facebook plugin to support Gradle #jira UE-48569 #ue4 #android #fyi Josh.Markiewicz #rb none #lockdown Peter.Sauerbrei Change 3595849 on 2017/08/17 by Chris.Babcock Fix issue with libovrplatformloader.so for non armv7 targets #jira UE-48533 #ue4 #android #rb none #lockdown Peter.Sauerbrei Change 3596419 on 2017/08/18 by Peter.Sauerbrei fix for Mac Editor build failure #rb none Change 3597023 on 2017/08/18 by Peter.Sauerbrei fix for game editor build failure #rb none Change 3597032 on 2017/08/18 by Peter.Sauerbrei fix for app bundle id in Info-Editor.plist #rb none Change 3597034 on 2017/08/18 by Peter.Sauerbrei put back the info.plist, found the real problem #rb none Change 3597197 on 2017/08/18 by Peter.Sauerbrei pull Info.plist from the build products #rb none [CL 3600450 by Chris Babcock in Main branch]
916 lines
30 KiB
C++
916 lines
30 KiB
C++
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Misc/App.h"
|
|
#include "Misc/OutputDeviceError.h"
|
|
#include "LaunchEngineLoop.h"
|
|
#include <string.h>
|
|
#include <jni.h>
|
|
#include <pthread.h>
|
|
#include "AndroidJNI.h"
|
|
#include "AndroidEventManager.h"
|
|
#include "AndroidInputInterface.h"
|
|
#include <android/log.h>
|
|
#include <android_native_app_glue.h>
|
|
#include <cstdio>
|
|
#include <sys/resource.h>
|
|
#include <dlfcn.h>
|
|
#include "AndroidWindow.h"
|
|
#include "AndroidApplication.h"
|
|
#include "PlatformApplicationMisc.h"
|
|
#include "IHeadMountedDisplayModule.h"
|
|
#include "ISessionServicesModule.h"
|
|
#include "ISessionService.h"
|
|
#include "Engine/Engine.h"
|
|
#include "HAL/PlatformFile.h"
|
|
#include "HAL/PlatformAffinity.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "IMessagingModule.h"
|
|
#include "AndroidStats.h"
|
|
|
|
// Function pointer for retrieving joystick events
|
|
// Function has been part of the OS since Honeycomb, but only appeared in the
|
|
// NDK in r19. Querying via dlsym allows its use without tying to the newest
|
|
// NDK.
|
|
typedef float(*GetAxesType)(const AInputEvent*, int32_t axis, size_t pointer_index);
|
|
static GetAxesType GetAxes = NULL;
|
|
|
|
// List of default axes to query for each controller
|
|
// Ideal solution is to call out to Java and enumerate the list of axes.
|
|
static const int32_t AxisList[] =
|
|
{
|
|
AMOTION_EVENT_AXIS_X,
|
|
AMOTION_EVENT_AXIS_Y,
|
|
AMOTION_EVENT_AXIS_Z,
|
|
AMOTION_EVENT_AXIS_RX,
|
|
AMOTION_EVENT_AXIS_RY,
|
|
AMOTION_EVENT_AXIS_RZ,
|
|
|
|
//These are DPAD analogs
|
|
AMOTION_EVENT_AXIS_HAT_X,
|
|
AMOTION_EVENT_AXIS_HAT_Y,
|
|
};
|
|
|
|
// map of all supported keycodes
|
|
static TSet<uint32> MappedKeyCodes;
|
|
|
|
// List of desired gamepad keycodes
|
|
static const uint32 ValidGamepadKeyCodesList[] =
|
|
{
|
|
AKEYCODE_BUTTON_A,
|
|
AKEYCODE_DPAD_CENTER,
|
|
AKEYCODE_BUTTON_B,
|
|
AKEYCODE_BUTTON_C,
|
|
AKEYCODE_BUTTON_X,
|
|
AKEYCODE_BUTTON_Y,
|
|
AKEYCODE_BUTTON_Z,
|
|
AKEYCODE_BUTTON_L1,
|
|
AKEYCODE_BUTTON_R1,
|
|
AKEYCODE_BUTTON_START,
|
|
AKEYCODE_MENU,
|
|
AKEYCODE_BUTTON_SELECT,
|
|
AKEYCODE_BACK,
|
|
AKEYCODE_BUTTON_THUMBL,
|
|
AKEYCODE_BUTTON_THUMBR,
|
|
AKEYCODE_BUTTON_L2,
|
|
AKEYCODE_BUTTON_R2,
|
|
AKEYCODE_DPAD_UP,
|
|
AKEYCODE_DPAD_DOWN,
|
|
AKEYCODE_DPAD_LEFT,
|
|
AKEYCODE_DPAD_RIGHT
|
|
};
|
|
|
|
// map of gamepad keycodes that should be passed forward
|
|
static TSet<uint32> ValidGamepadKeyCodes;
|
|
|
|
// -nostdlib means no crtbegin_so.o, so we have to provide our own __dso_handle and atexit()
|
|
extern "C"
|
|
{
|
|
int atexit(void (*func)(void)) { return 0; }
|
|
|
|
extern void *__dso_handle __attribute__((__visibility__ ("hidden")));
|
|
void *__dso_handle;
|
|
}
|
|
|
|
extern void AndroidThunkCpp_InitHMDs();
|
|
extern void AndroidThunkCpp_ShowConsoleWindow();
|
|
extern bool AndroidThunkCpp_IsVirtuaInputClicked(int, int);
|
|
|
|
// Base path for file accesses
|
|
extern FString GFilePathBase;
|
|
|
|
/** The global EngineLoop instance */
|
|
FEngineLoop GEngineLoop;
|
|
|
|
bool GShowConsoleWindowNextTick = false;
|
|
|
|
static void AndroidProcessEvents(struct android_app* state);
|
|
|
|
//Event thread stuff
|
|
static void* AndroidEventThreadWorker(void* param);
|
|
|
|
// How often to process (read & dispatch) events, in seconds.
|
|
static const float EventRefreshRate = 1.0f / 20.0f;
|
|
|
|
//Android event callback functions
|
|
static int32_t HandleInputCB(struct android_app* app, AInputEvent* event); //Touch and key input events
|
|
static void OnAppCommandCB(struct android_app* app, int32_t cmd); //Lifetime events
|
|
|
|
|
|
bool GHasInterruptionRequest = false;
|
|
bool GIsInterrupted = false;
|
|
|
|
// Set 'SustainedPerformanceMode' via cvar sink.
|
|
static TAutoConsoleVariable<int32> CVarEnableSustainedPerformanceMode(
|
|
TEXT("Android.EnableSustainedPerformanceMode"),
|
|
0,
|
|
TEXT("Enable sustained performance mode, if supported. (API >= 24 req. not supported by all devices.)\n")
|
|
TEXT(" 0: Disabled (default)\n")
|
|
TEXT(" 1: Enabled"),
|
|
ECVF_Default);
|
|
|
|
extern void AndroidThunkCpp_SetSustainedPerformanceMode(bool);
|
|
static void SetSustainedPerformanceMode()
|
|
{
|
|
bool bSustainedPerformanceMode = CVarEnableSustainedPerformanceMode.GetValueOnAnyThread() != 0;
|
|
UE_LOG(LogAndroid, Log, TEXT("Setting sustained performance mode: %d"), (int32)bSustainedPerformanceMode);
|
|
AndroidThunkCpp_SetSustainedPerformanceMode(bSustainedPerformanceMode);
|
|
}
|
|
FAutoConsoleVariableSink CVarEnableSustainedPerformanceModeSink(FConsoleCommandDelegate::CreateStatic(&SetSustainedPerformanceMode));
|
|
|
|
// Event for coordinating pausing of the main and event handling threads to prevent background spinning
|
|
static FEvent* EventHandlerEvent = NULL;
|
|
|
|
// Wait for Java onCreate to complete before resume main init
|
|
static volatile bool GResumeMainInit = false;
|
|
volatile bool GEventHandlerInitialized = false;
|
|
|
|
//virtualKeyboard shown
|
|
static volatile bool GVirtualKeyboardShown = false;
|
|
|
|
JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeResumeMainInit(JNIEnv* jenv, jobject thiz)
|
|
{
|
|
GResumeMainInit = true;
|
|
|
|
// now wait for event handler to be set up before returning
|
|
while (!GEventHandlerInitialized)
|
|
{
|
|
FPlatformProcess::Sleep(0.01f);
|
|
FPlatformMisc::MemoryBarrier();
|
|
}
|
|
}
|
|
|
|
static volatile bool GHMDsInitialized = false;
|
|
static TArray<IHeadMountedDisplayModule*> GHMDImplementations;
|
|
void InitHMDs()
|
|
{
|
|
if (FParse::Param(FCommandLine::Get(), TEXT("nohmd")) || FParse::Param(FCommandLine::Get(), TEXT("emulatestereo")))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get a list of plugins that implement this feature
|
|
GHMDImplementations = IModularFeatures::Get().GetModularFeatureImplementations<IHeadMountedDisplayModule>(IHeadMountedDisplayModule::GetModularFeatureName());
|
|
|
|
AndroidThunkCpp_InitHMDs();
|
|
|
|
while (!GHMDsInitialized)
|
|
{
|
|
FPlatformProcess::Sleep(0.01f);
|
|
FPlatformMisc::MemoryBarrier();
|
|
}
|
|
}
|
|
|
|
static void InitCommandLine()
|
|
{
|
|
static const uint32 CMD_LINE_MAX = 16384u;
|
|
|
|
// initialize the command line to an empty string
|
|
FCommandLine::Set(TEXT(""));
|
|
|
|
// read in the command line text file from the sdcard if it exists
|
|
FString CommandLineFilePath = GFilePathBase + FString("/UE4Game/") + (!FApp::IsProjectNameEmpty() ? FApp::GetProjectName() : FPlatformProcess::ExecutableName()) + FString("/UE4CommandLine.txt");
|
|
FILE* CommandLineFile = fopen(TCHAR_TO_UTF8(*CommandLineFilePath), "r");
|
|
if(CommandLineFile == NULL)
|
|
{
|
|
// if that failed, try the lowercase version
|
|
CommandLineFilePath = CommandLineFilePath.Replace(TEXT("UE4CommandLine.txt"), TEXT("ue4commandline.txt"));
|
|
CommandLineFile = fopen(TCHAR_TO_UTF8(*CommandLineFilePath), "r");
|
|
}
|
|
|
|
if(CommandLineFile)
|
|
{
|
|
char CommandLine[CMD_LINE_MAX];
|
|
fgets(CommandLine, ARRAY_COUNT(CommandLine) - 1, CommandLineFile);
|
|
|
|
fclose(CommandLineFile);
|
|
|
|
// chop off trailing spaces
|
|
while (*CommandLine && isspace(CommandLine[strlen(CommandLine) - 1]))
|
|
{
|
|
CommandLine[strlen(CommandLine) - 1] = 0;
|
|
}
|
|
|
|
FCommandLine::Append(UTF8_TO_TCHAR(CommandLine));
|
|
}
|
|
}
|
|
|
|
extern void AndroidThunkCpp_DismissSplashScreen();
|
|
|
|
//Main function called from the android entry point
|
|
int32 AndroidMain(struct android_app* state)
|
|
{
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Entered AndroidMain()");
|
|
|
|
// Force the first call to GetJavaEnv() to happen on the game thread, allowing subsequent calls to occur on any thread
|
|
FAndroidApplication::GetJavaEnv();
|
|
|
|
// Set window format to 8888
|
|
ANativeActivity_setWindowFormat(state->activity, WINDOW_FORMAT_RGBA_8888);
|
|
|
|
// adjust the file descriptor limits to allow as many open files as possible
|
|
rlimit cur_fd_limit;
|
|
{
|
|
int result = getrlimit(RLIMIT_NOFILE, & cur_fd_limit);
|
|
//FPlatformMisc::LowLevelOutputDebugStringf(TEXT("(%d) Current fd limits: soft = %lld, hard = %lld"), result, cur_fd_limit.rlim_cur, cur_fd_limit.rlim_max);
|
|
}
|
|
{
|
|
rlimit new_limit = cur_fd_limit;
|
|
new_limit.rlim_cur = cur_fd_limit.rlim_max;
|
|
new_limit.rlim_max = cur_fd_limit.rlim_max;
|
|
int result = setrlimit(RLIMIT_NOFILE, &new_limit);
|
|
//FPlatformMisc::LowLevelOutputDebugStringf(TEXT("(%d) Setting fd limits: soft = %lld, hard = %lld"), result, new_limit.rlim_cur, new_limit.rlim_max);
|
|
}
|
|
{
|
|
int result = getrlimit(RLIMIT_NOFILE, & cur_fd_limit);
|
|
//FPlatformMisc::LowLevelOutputDebugStringf(TEXT("(%d) Current fd limits: soft = %lld, hard = %lld"), result, cur_fd_limit.rlim_cur, cur_fd_limit.rlim_max);
|
|
}
|
|
|
|
// setup joystick support
|
|
// r19 is the first NDK to include AMotionEvent_getAxisValue in the headers
|
|
// However, it has existed in the so since Honeycomb, query for the symbol
|
|
// to determine whether to try controller support
|
|
{
|
|
void* Lib = dlopen("libandroid.so",0);
|
|
if (Lib != NULL)
|
|
{
|
|
GetAxes = (GetAxesType)dlsym(Lib, "AMotionEvent_getAxisValue");
|
|
}
|
|
|
|
if (GetAxes != NULL)
|
|
{
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Controller interface supported\n"));
|
|
}
|
|
else
|
|
{
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Controller interface UNsupported\n"));
|
|
}
|
|
}
|
|
|
|
// setup key filtering
|
|
static const uint32 MAX_KEY_MAPPINGS(256);
|
|
uint32 KeyCodes[MAX_KEY_MAPPINGS];
|
|
uint32 NumKeyCodes = FPlatformApplicationMisc::GetKeyMap(KeyCodes, nullptr, MAX_KEY_MAPPINGS);
|
|
|
|
for (int i = 0; i < NumKeyCodes; ++i)
|
|
{
|
|
MappedKeyCodes.Add(KeyCodes[i]);
|
|
}
|
|
|
|
const int ValidGamepadKeyCodeCount = sizeof(ValidGamepadKeyCodesList)/sizeof(uint32);
|
|
for (int i = 0; i < ValidGamepadKeyCodeCount; ++i)
|
|
{
|
|
ValidGamepadKeyCodes.Add(ValidGamepadKeyCodesList[i]);
|
|
}
|
|
|
|
// wait for java activity onCreate to finish
|
|
while (!GResumeMainInit)
|
|
{
|
|
FPlatformProcess::Sleep(0.01f);
|
|
FPlatformMisc::MemoryBarrier();
|
|
}
|
|
|
|
// read the command line file
|
|
InitCommandLine();
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Final commandline: %s\n"), FCommandLine::Get());
|
|
|
|
EventHandlerEvent = FPlatformProcess::GetSynchEventFromPool(false);
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Created sync event");
|
|
FAppEventManager::GetInstance()->SetEventHandlerEvent(EventHandlerEvent);
|
|
|
|
// ready for onCreate to complete
|
|
GEventHandlerInitialized = true;
|
|
|
|
// Initialize file system access (i.e. mount OBBs, etc.).
|
|
// We need to do this really early for Android so that files in the
|
|
// OBBs and APK are found.
|
|
IPlatformFile::GetPlatformPhysical().Initialize(nullptr, FCommandLine::Get());
|
|
|
|
// initialize the engine
|
|
GEngineLoop.PreInit(0, NULL, FCommandLine::Get());
|
|
|
|
// initialize HMDs
|
|
InitHMDs();
|
|
|
|
UE_LOG(LogAndroid, Display, TEXT("Passed PreInit()"));
|
|
|
|
GLog->SetCurrentThreadAsMasterThread();
|
|
|
|
GEngineLoop.Init();
|
|
|
|
UE_LOG(LogAndroid, Log, TEXT("Passed GEngineLoop.Init()"));
|
|
|
|
AndroidThunkCpp_DismissSplashScreen();
|
|
|
|
FAppEventManager::GetInstance()->SetEmptyQueueHandlerEvent(FPlatformProcess::GetSynchEventFromPool(false));
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
if (FParse::Param(FCommandLine::Get(), TEXT("Messaging")))
|
|
{
|
|
// initialize messaging subsystem
|
|
FModuleManager::LoadModuleChecked<IMessagingModule>("Messaging");
|
|
TSharedPtr<ISessionService> SessionService = FModuleManager::LoadModuleChecked<ISessionServicesModule>("SessionServices").GetSessionService();
|
|
SessionService->Start();
|
|
|
|
// Initialize functional testing
|
|
FModuleManager::Get().LoadModule("FunctionalTesting");
|
|
}
|
|
#endif
|
|
|
|
// tick until done
|
|
while (!GIsRequestingExit)
|
|
{
|
|
FAndroidStats::UpdateAndroidStats();
|
|
|
|
FAppEventManager::GetInstance()->Tick();
|
|
if(!FAppEventManager::GetInstance()->IsGamePaused())
|
|
{
|
|
GEngineLoop.Tick();
|
|
}
|
|
else
|
|
{
|
|
// use less CPU when paused
|
|
FPlatformProcess::Sleep(0.10f);
|
|
}
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
// show console window on next game tick
|
|
if (GShowConsoleWindowNextTick)
|
|
{
|
|
GShowConsoleWindowNextTick = false;
|
|
AndroidThunkCpp_ShowConsoleWindow();
|
|
}
|
|
#endif
|
|
}
|
|
FAppEventManager::GetInstance()->TriggerEmptyQueue();
|
|
|
|
UE_LOG(LogAndroid, Log, TEXT("Exiting"));
|
|
|
|
// exit out!
|
|
GEngineLoop.Exit();
|
|
|
|
UE_LOG(LogAndroid, Log, TEXT("Exiting is over"));
|
|
|
|
FPlatformMisc::RequestExit(1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static void* AndroidEventThreadWorker( void* param )
|
|
{
|
|
struct android_app* state = (struct android_app*)param;
|
|
|
|
FPlatformProcess::SetThreadAffinityMask(FPlatformAffinity::GetMainGameMask());
|
|
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Entering event processing thread engine entry point");
|
|
|
|
ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
|
ALooper_addFd(looper, state->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
|
|
&state->cmdPollSource);
|
|
state->looper = looper;
|
|
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Prepared looper for event thread");
|
|
|
|
//Assign the callbacks
|
|
state->onAppCmd = OnAppCommandCB;
|
|
state->onInputEvent = HandleInputCB;
|
|
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Passed callback initialization");
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Passed sensor initialization");
|
|
|
|
//continue to process events until the engine is shutting down
|
|
while (!GIsRequestingExit)
|
|
{
|
|
// FPlatformMisc::LowLevelOutputDebugString(L"AndroidEventThreadWorker");
|
|
|
|
AndroidProcessEvents(state);
|
|
|
|
sleep(EventRefreshRate); // this is really 0 since it takes int seconds.
|
|
}
|
|
|
|
UE_LOG(LogAndroid, Log, TEXT("Exiting"));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//Called from the separate event processing thread
|
|
static void AndroidProcessEvents(struct android_app* state)
|
|
{
|
|
int ident;
|
|
int fdesc;
|
|
int events;
|
|
struct android_poll_source* source;
|
|
|
|
while((ident = ALooper_pollAll(-1, &fdesc, &events, (void**)&source)) >= 0)
|
|
{
|
|
// process this event
|
|
if (source)
|
|
{
|
|
source->process(state, source);
|
|
}
|
|
}
|
|
}
|
|
|
|
pthread_t G_AndroidEventThread;
|
|
|
|
struct android_app* GNativeAndroidApp = NULL;
|
|
|
|
void android_main(struct android_app* state)
|
|
{
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Entering native app glue main function");
|
|
|
|
GNativeAndroidApp = state;
|
|
check(GNativeAndroidApp);
|
|
|
|
pthread_attr_t otherAttr;
|
|
pthread_attr_init(&otherAttr);
|
|
pthread_attr_setdetachstate(&otherAttr, PTHREAD_CREATE_DETACHED);
|
|
pthread_create(&G_AndroidEventThread, &otherAttr, AndroidEventThreadWorker, state);
|
|
|
|
FPlatformMisc::LowLevelOutputDebugString(L"Created event thread");
|
|
|
|
// Make sure glue isn't stripped. (not needed in ndk-15)
|
|
#if PLATFORM_ANDROID_NDK_VERSION < 150000
|
|
app_dummy();
|
|
#endif
|
|
|
|
//@todo android: replace with native activity, main loop off of UI thread, etc.
|
|
AndroidMain(state);
|
|
}
|
|
|
|
extern bool GAndroidGPUInfoReady;
|
|
|
|
//Called from the event process thread
|
|
static int32_t HandleInputCB(struct android_app* app, AInputEvent* event)
|
|
{
|
|
// FPlatformMisc::LowLevelOutputDebugStringf(L"INPUT - type: %x, action: %x, source: %x, keycode: %x, buttons: %x", AInputEvent_getType(event),
|
|
// AMotionEvent_getAction(event), AInputEvent_getSource(event), AKeyEvent_getKeyCode(event), AMotionEvent_getButtonState(event));
|
|
|
|
int32 EventType = AInputEvent_getType(event);
|
|
int32 EventSource = AInputEvent_getSource(event);
|
|
|
|
if (EventType == AINPUT_EVENT_TYPE_MOTION)
|
|
{
|
|
int action = AMotionEvent_getAction(event);
|
|
int actionType = action & AMOTION_EVENT_ACTION_MASK;
|
|
size_t actionPointer = (size_t)((action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
|
|
bool isActionTargeted = (actionType == AMOTION_EVENT_ACTION_POINTER_DOWN || actionType == AMOTION_EVENT_ACTION_POINTER_UP);
|
|
int32 device = AInputEvent_getDeviceId(event);
|
|
|
|
// trap Joystick events first, with fallthrough if there is no joystick support
|
|
if (((EventSource & AINPUT_SOURCE_CLASS_JOYSTICK) == AINPUT_SOURCE_CLASS_JOYSTICK) &&
|
|
(GetAxes != NULL) &&
|
|
(actionType == AMOTION_EVENT_ACTION_MOVE))
|
|
{
|
|
const int axisCount = sizeof(AxisList)/sizeof(int32_t);
|
|
|
|
// poll all the axes and forward to update controller state
|
|
for (int axis = 0; axis < axisCount; axis++)
|
|
{
|
|
float val = GetAxes( event, AxisList[axis], 0);
|
|
FAndroidInputInterface::JoystickAxisEvent(device, AxisList[axis], val);
|
|
}
|
|
|
|
// handle L/R trigger and Brake/Gas special (all in 0..1 range)
|
|
// LTRIGGER will either be LTRIGGER or BRAKE, whichever is larger
|
|
// RTRIGGER will either be RTRIGGER or GAS, whichever is larger
|
|
float ltrigger = GetAxes(event, AMOTION_EVENT_AXIS_LTRIGGER, 0);
|
|
float rtrigger = GetAxes(event, AMOTION_EVENT_AXIS_RTRIGGER, 0);
|
|
float brake = GetAxes(event, AMOTION_EVENT_AXIS_BRAKE, 0);
|
|
float gas = GetAxes(event, AMOTION_EVENT_AXIS_GAS, 0);
|
|
FAndroidInputInterface::JoystickAxisEvent(device, AMOTION_EVENT_AXIS_LTRIGGER, ltrigger > brake ? ltrigger : brake);
|
|
FAndroidInputInterface::JoystickAxisEvent(device, AMOTION_EVENT_AXIS_RTRIGGER, rtrigger > gas ? rtrigger : gas);
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
TArray<TouchInput> TouchesArray;
|
|
|
|
TouchType type = TouchEnded;
|
|
|
|
switch (actionType)
|
|
{
|
|
case AMOTION_EVENT_ACTION_DOWN:
|
|
case AMOTION_EVENT_ACTION_POINTER_DOWN:
|
|
type = TouchBegan;
|
|
break;
|
|
case AMOTION_EVENT_ACTION_MOVE:
|
|
type = TouchMoved;
|
|
break;
|
|
case AMOTION_EVENT_ACTION_UP:
|
|
case AMOTION_EVENT_ACTION_POINTER_UP:
|
|
case AMOTION_EVENT_ACTION_CANCEL:
|
|
case AMOTION_EVENT_ACTION_OUTSIDE:
|
|
type = TouchEnded;
|
|
break;
|
|
case AMOTION_EVENT_ACTION_SCROLL:
|
|
case AMOTION_EVENT_ACTION_HOVER_ENTER:
|
|
case AMOTION_EVENT_ACTION_HOVER_MOVE:
|
|
case AMOTION_EVENT_ACTION_HOVER_EXIT:
|
|
return 0;
|
|
default:
|
|
UE_LOG(LogAndroid, Verbose, TEXT("Unknown AMOTION_EVENT %d ignored"), actionType);
|
|
return 0;
|
|
}
|
|
|
|
size_t pointerCount = AMotionEvent_getPointerCount(event);
|
|
|
|
if (pointerCount == 0)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
ANativeWindow* Window = (ANativeWindow*)FPlatformMisc::GetHardwareWindow();
|
|
if (!Window)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int32_t Width = 0 ;
|
|
int32_t Height = 0 ;
|
|
|
|
if(Window)
|
|
{
|
|
FAndroidWindow::CalculateSurfaceSize(Window, Width, Height);
|
|
}
|
|
|
|
// make sure OpenGL context created before accepting touch events.. FAndroidWindow::GetScreenRect() may try to create it early from wrong thread if this is the first call
|
|
if (!GAndroidGPUInfoReady)
|
|
{
|
|
return 1;
|
|
}
|
|
FPlatformRect ScreenRect = FAndroidWindow::GetScreenRect();
|
|
|
|
if (GVirtualKeyboardShown && (type == TouchBegan || type == TouchMoved))
|
|
{
|
|
int pointerId = AMotionEvent_getPointerId(event, actionPointer);
|
|
int32 x = AMotionEvent_getX(event, actionPointer);
|
|
int32 y = AMotionEvent_getY(event, actionPointer);
|
|
|
|
//ignore key down events when the native input was clicked
|
|
if(AndroidThunkCpp_IsVirtuaInputClicked(x, y))
|
|
return 0;
|
|
}
|
|
if(isActionTargeted)
|
|
{
|
|
if(actionPointer < 0 || pointerCount < (int)actionPointer)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int pointerId = AMotionEvent_getPointerId(event, actionPointer);
|
|
float x = FMath::Min<float>(AMotionEvent_getX(event, actionPointer) / Width, 1.f);
|
|
x *= (ScreenRect.Right - 1);
|
|
float y = FMath::Min<float>(AMotionEvent_getY(event, actionPointer) / Height, 1.f);
|
|
y *= (ScreenRect.Bottom - 1);
|
|
|
|
UE_LOG(LogAndroid, Verbose, TEXT("Received targeted motion event from pointer %u (id %d) action %d: (%.2f, %.2f)"), actionPointer, pointerId, action, x, y);
|
|
|
|
TouchInput TouchMessage;
|
|
TouchMessage.DeviceId = device;
|
|
TouchMessage.Handle = pointerId;
|
|
TouchMessage.Type = type;
|
|
TouchMessage.Position = FVector2D(x, y);
|
|
TouchMessage.LastPosition = FVector2D(x, y); //@todo android: AMotionEvent_getHistoricalRawX
|
|
TouchesArray.Add(TouchMessage);
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < pointerCount; ++i)
|
|
{
|
|
int pointerId = AMotionEvent_getPointerId(event, i);
|
|
|
|
float x = FMath::Min<float>(AMotionEvent_getX(event, i) / Width, 1.f);
|
|
x *= (ScreenRect.Right - 1);
|
|
float y = FMath::Min<float>(AMotionEvent_getY(event, i) / Height, 1.f);
|
|
y *= (ScreenRect.Bottom - 1);
|
|
|
|
UE_LOG(LogAndroid, Verbose, TEXT("Received motion event from index %u (id %d) action %d: (%.2f, %.2f)"), i, pointerId, action, x, y);
|
|
|
|
TouchInput TouchMessage;
|
|
TouchMessage.DeviceId= device;
|
|
TouchMessage.Handle = pointerId;
|
|
TouchMessage.Type = type;
|
|
TouchMessage.Position = FVector2D(x, y);
|
|
TouchMessage.LastPosition = FVector2D(x, y); //@todo android: AMotionEvent_getHistoricalRawX
|
|
TouchesArray.Add(TouchMessage);
|
|
}
|
|
}
|
|
|
|
FAndroidInputInterface::QueueTouchInput(TouchesArray);
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
if ((pointerCount >= 4) && (type == TouchBegan))
|
|
{
|
|
bool bShowConsole = true;
|
|
GConfig->GetBool(TEXT("/Script/Engine.InputSettings"), TEXT("bShowConsoleOnFourFingerTap"), bShowConsole, GInputIni);
|
|
|
|
if (bShowConsole)
|
|
{
|
|
GShowConsoleWindowNextTick = true;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (EventType == AINPUT_EVENT_TYPE_KEY)
|
|
{
|
|
int keyCode = AKeyEvent_getKeyCode(event);
|
|
|
|
FPlatformMisc::LowLevelOutputDebugStringf(L"Received keycode: %d", keyCode);
|
|
|
|
//Trap codes handled as possible gamepad events
|
|
if (ValidGamepadKeyCodes.Contains(keyCode))
|
|
{
|
|
//Only pass on the device id if really a gamepad, joystick or dpad (allows menu and back to be treated as gamepad events)
|
|
int32 device = 0;
|
|
if ( (((EventSource & AINPUT_SOURCE_JOYSTICK) == AINPUT_SOURCE_JOYSTICK) && (GetAxes != NULL)) ||
|
|
((EventSource & AINPUT_SOURCE_GAMEPAD) == AINPUT_SOURCE_GAMEPAD) ||
|
|
((EventSource & AINPUT_SOURCE_DPAD) == AINPUT_SOURCE_DPAD) )
|
|
{
|
|
device = AInputEvent_getDeviceId(event);
|
|
}
|
|
bool down = AKeyEvent_getAction(event) != AKEY_EVENT_ACTION_UP;
|
|
FAndroidInputInterface::JoystickButtonEvent(device, keyCode, down);
|
|
FPlatformMisc::LowLevelOutputDebugStringf(L"Received gamepad button: %d", keyCode);
|
|
}
|
|
else
|
|
{
|
|
FPlatformMisc::LowLevelOutputDebugStringf(L"Received key event: %d", keyCode);
|
|
|
|
// only handle mapped key codes
|
|
if (!MappedKeyCodes.Contains(keyCode))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
FDeferredAndroidMessage Message;
|
|
|
|
Message.messageType = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_UP ? MessageType_KeyUp : MessageType_KeyDown;
|
|
Message.KeyEventData.unichar = keyCode;
|
|
Message.KeyEventData.keyId = keyCode;
|
|
Message.KeyEventData.modifier = AKeyEvent_getMetaState(event);
|
|
Message.KeyEventData.isRepeat = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE;
|
|
FAndroidInputInterface::DeferMessage(Message);
|
|
|
|
// allow event to be generated for volume up and down, but conditionally allow system to handle it, too
|
|
if (keyCode == AKEYCODE_VOLUME_UP || keyCode == AKEYCODE_VOLUME_DOWN)
|
|
{
|
|
if (FPlatformMisc::GetVolumeButtonsHandledBySystem())
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//Called from the event process thread
|
|
static void OnAppCommandCB(struct android_app* app, int32_t cmd)
|
|
{
|
|
bool bNeedToSync = false;
|
|
//FPlatformMisc::LowLevelOutputDebugStringf(L"OnAppCommandCB cmd: %u, tid = %d", cmd, gettid());
|
|
|
|
switch (cmd)
|
|
{
|
|
case APP_CMD_SAVE_STATE:
|
|
/**
|
|
* Command from main thread: the app should generate a new saved state
|
|
* for itself, to restore from later if needed. If you have saved state,
|
|
* allocate it with malloc and place it in android_app.savedState with
|
|
* the size in android_app.savedStateSize. The will be freed for you
|
|
* later.
|
|
*/
|
|
// the OS asked us to save the state of the app
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_SAVE_STATE"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_SAVE_STATE);
|
|
break;
|
|
case APP_CMD_INIT_WINDOW:
|
|
/**
|
|
* Command from main thread: a new ANativeWindow is ready for use. Upon
|
|
* receiving this command, android_app->window will contain the new window
|
|
* surface.
|
|
*/
|
|
// get the window ready for showing
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Case APP_CMD_INIT_WINDOW"));
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_INIT_WINDOW"));
|
|
FAppEventManager::GetInstance()->HandleWindowCreated(app->pendingWindow);
|
|
|
|
bNeedToSync = true;
|
|
break;
|
|
case APP_CMD_TERM_WINDOW:
|
|
/**
|
|
* Command from main thread: the existing ANativeWindow needs to be
|
|
* terminated. Upon receiving this command, android_app->window still
|
|
* contains the existing window; after calling android_app_exec_cmd
|
|
* it will be set to NULL.
|
|
*/
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Case APP_CMD_TERM_WINDOW, tid = %d"), gettid());
|
|
// clean up the window because it is being hidden/closed
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_TERM_WINDOW"));
|
|
FAppEventManager::GetInstance()->HandleWindowClosed();
|
|
|
|
bNeedToSync = true;
|
|
break;
|
|
case APP_CMD_LOST_FOCUS:
|
|
/**
|
|
* Command from main thread: the app's activity window has lost
|
|
* input focus.
|
|
*/
|
|
// if the app lost focus, avoid unnecessary processing (like monitoring the accelerometer)
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_LOST_FOCUS"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_WINDOW_LOST_FOCUS, NULL);
|
|
break;
|
|
case APP_CMD_GAINED_FOCUS:
|
|
/**
|
|
* Command from main thread: the app's activity window has gained
|
|
* input focus.
|
|
*/
|
|
// bring back a certain functionality, like monitoring the accelerometer
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_GAINED_FOCUS"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_WINDOW_GAINED_FOCUS, NULL);
|
|
break;
|
|
case APP_CMD_INPUT_CHANGED:
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_INPUT_CHANGED"));
|
|
break;
|
|
case APP_CMD_WINDOW_RESIZED:
|
|
/**
|
|
* Command from main thread: the current ANativeWindow has been resized.
|
|
* Please redraw with its new size.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_WINDOW_RESIZED"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_WINDOW_RESIZED );
|
|
break;
|
|
case APP_CMD_WINDOW_REDRAW_NEEDED:
|
|
/**
|
|
* Command from main thread: the system needs that the current ANativeWindow
|
|
* be redrawn. You should redraw the window before handing this to
|
|
* android_app_exec_cmd() in order to avoid transient drawing glitches.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_WINDOW_REDRAW_NEEDED"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_WINDOW_REDRAW_NEEDED );
|
|
break;
|
|
case APP_CMD_CONTENT_RECT_CHANGED:
|
|
/**
|
|
* Command from main thread: the content area of the window has changed,
|
|
* such as from the soft input window being shown or hidden. You can
|
|
* find the new content rect in android_app::contentRect.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_CONTENT_RECT_CHANGED"));
|
|
break;
|
|
case APP_CMD_CONFIG_CHANGED:
|
|
{
|
|
/**
|
|
* Command from main thread: the current device configuration has changed.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_CONFIG_CHANGED"));
|
|
|
|
bool bPortrait = (AConfiguration_getOrientation(app->config) == ACONFIGURATION_ORIENTATION_PORT);
|
|
if (FAndroidWindow::OnWindowOrientationChanged(bPortrait))
|
|
{
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_WINDOW_CHANGED, nullptr);
|
|
}
|
|
}
|
|
break;
|
|
case APP_CMD_LOW_MEMORY:
|
|
/**
|
|
* Command from main thread: the system is running low on memory.
|
|
* Try to reduce your memory use.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_LOW_MEMORY"));
|
|
break;
|
|
case APP_CMD_START:
|
|
/**
|
|
* Command from main thread: the app's activity has been started.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_START"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_ON_START);
|
|
|
|
break;
|
|
case APP_CMD_RESUME:
|
|
/**
|
|
* Command from main thread: the app's activity has been resumed.
|
|
*/
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Case APP_CMD_RESUME"));
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_RESUME"));
|
|
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_ON_RESUME);
|
|
|
|
break;
|
|
case APP_CMD_PAUSE:
|
|
/**
|
|
* Command from main thread: the app's activity has been paused.
|
|
*/
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Case APP_CMD_PAUSE"));
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_PAUSE"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_ON_PAUSE);
|
|
|
|
bNeedToSync = true;
|
|
break;
|
|
case APP_CMD_STOP:
|
|
/**
|
|
* Command from main thread: the app's activity has been stopped.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_STOP"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_ON_STOP);
|
|
|
|
break;
|
|
case APP_CMD_DESTROY:
|
|
/**
|
|
* Command from main thread: the app's activity is being destroyed,
|
|
* and waiting for the app thread to clean up and exit before proceeding.
|
|
*/
|
|
UE_LOG(LogAndroid, Log, TEXT("Case APP_CMD_DESTROY"));
|
|
FAppEventManager::GetInstance()->EnqueueAppEvent(APP_EVENT_STATE_ON_DESTROY);
|
|
break;
|
|
}
|
|
|
|
if ( EventHandlerEvent )
|
|
EventHandlerEvent->Trigger();
|
|
|
|
if (bNeedToSync)
|
|
FAppEventManager::GetInstance()->WaitForEmptyQueue();
|
|
//FPlatformMisc::LowLevelOutputDebugStringf(L"#### END OF OnAppCommandCB cmd: %u, tid = %d", cmd, gettid());
|
|
}
|
|
|
|
//Native-defined functions
|
|
|
|
//Set GVirtualKeyboardShown.This function is declared in the Java-defined class, GameActivity.java: "public native void nativeVirtualKeyboardVisible(boolean bShown)"
|
|
JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeVirtualKeyboardVisible(JNIEnv* jenv, jobject thiz, jboolean bShown)
|
|
{
|
|
GVirtualKeyboardShown = bShown;
|
|
}
|
|
|
|
//This function is declared in the Java-defined class, GameActivity.java: "public native void nativeConsoleCommand(String commandString);"
|
|
JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeConsoleCommand(JNIEnv* jenv, jobject thiz, jstring commandString)
|
|
{
|
|
const char* javaChars = jenv->GetStringUTFChars(commandString, 0);
|
|
|
|
new(GEngine->DeferredCommands) FString(UTF8_TO_TCHAR(javaChars));
|
|
|
|
//Release the string
|
|
jenv->ReleaseStringUTFChars(commandString, javaChars);
|
|
}
|
|
|
|
// This is called from the Java UI thread for initializing VR HMDs
|
|
JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeInitHMDs(JNIEnv* jenv, jobject thiz)
|
|
{
|
|
for (auto HMDModuleIt = GHMDImplementations.CreateIterator(); HMDModuleIt; ++HMDModuleIt)
|
|
{
|
|
(*HMDModuleIt)->PreInit();
|
|
}
|
|
|
|
GHMDsInitialized = true;
|
|
}
|
|
|
|
JNI_METHOD void Java_com_epicgames_ue4_GameActivity_nativeSetAndroidVersionInformation(JNIEnv* jenv, jobject thiz, jstring androidVersion, jstring phoneMake, jstring phoneModel, jstring osLanguage )
|
|
{
|
|
const char *javaAndroidVersion = jenv->GetStringUTFChars(androidVersion, 0 );
|
|
FString UEAndroidVersion = FString(UTF8_TO_TCHAR( javaAndroidVersion ));
|
|
|
|
const char *javaPhoneMake = jenv->GetStringUTFChars(phoneMake, 0 );
|
|
FString UEPhoneMake = FString(UTF8_TO_TCHAR( javaPhoneMake ));
|
|
|
|
const char *javaPhoneModel = jenv->GetStringUTFChars(phoneModel, 0 );
|
|
FString UEPhoneModel = FString(UTF8_TO_TCHAR( javaPhoneModel ));
|
|
|
|
const char *javaOSLanguage = jenv->GetStringUTFChars(osLanguage, 0);
|
|
FString UEOSLanguage = FString(UTF8_TO_TCHAR(javaOSLanguage));
|
|
|
|
FAndroidMisc::SetVersionInfo( UEAndroidVersion, UEPhoneMake, UEPhoneModel, UEOSLanguage );
|
|
}
|
|
|
|
bool WaitForAndroidLoseFocusEvent(double TimeoutSeconds)
|
|
{
|
|
return FAppEventManager::GetInstance()->WaitForEventInQueue(EAppEventState::APP_EVENT_STATE_WINDOW_LOST_FOCUS, TimeoutSeconds);
|
|
}
|