You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3209340 on 2016/11/23 by Ben.Marsh Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h. Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms. * Every header now includes everything it needs to compile. * There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first. * There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h. * Every .cpp file includes its matching .h file first. * This helps validate that each header is including everything it needs to compile. * No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more. * You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there. * There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible. * No engine code explicitly includes a precompiled header any more. * We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies. * PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files. Tool used to generate this transform is at Engine\Source\Programs\IncludeTool. [CL 3209342 by Ben Marsh in Main branch]
509 lines
16 KiB
C++
509 lines
16 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
AndroidTargetPlatform.inl: Implements the FAndroidTargetPlatform class.
|
|
=============================================================================*/
|
|
|
|
|
|
/* FAndroidTargetPlatform structors
|
|
*****************************************************************************/
|
|
|
|
#include "CoreTypes.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Containers/Array.h"
|
|
#include "Containers/UnrealString.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "Logging/LogMacros.h"
|
|
#include "Stats/Stats.h"
|
|
#define LOCTEXT_NAMESPACE "FAndroidTargetPlatform"
|
|
|
|
class Error;
|
|
class FAndroidTargetDevice;
|
|
class FConfigCacheIni;
|
|
class FModuleManager;
|
|
class FScopeLock;
|
|
class FStaticMeshLODSettings;
|
|
class FTargetDeviceId;
|
|
class FTicker;
|
|
class IAndroidDeviceDetectionModule;
|
|
class UTexture;
|
|
class UTextureLODSettings;
|
|
struct FAndroidDeviceInfo;
|
|
enum class ETargetPlatformFeatures;
|
|
template<class TPlatformProperties> class FAndroidTargetPlatform;
|
|
template<typename TPlatformProperties> class TTargetPlatformBase;
|
|
|
|
static bool SupportsES2()
|
|
{
|
|
// default to support ES2
|
|
bool bBuildForES2 = true;
|
|
GConfig->GetBool(TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"), TEXT("bBuildForES2"), bBuildForES2, GEngineIni);
|
|
return bBuildForES2;
|
|
}
|
|
|
|
static bool SupportsES31()
|
|
{
|
|
// default to support ES3
|
|
bool bBuildForES31 = false;
|
|
GConfig->GetBool(TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"), TEXT("bBuildForES31"), bBuildForES31, GEngineIni);
|
|
return bBuildForES31;
|
|
}
|
|
|
|
static bool SupportsAEP()
|
|
{
|
|
// default to not supporting ES31
|
|
bool bBuildForESDeferred = false;
|
|
GConfig->GetBool(TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"), TEXT("bBuildForESDeferred"), bBuildForESDeferred, GEngineIni);
|
|
return bBuildForESDeferred;
|
|
}
|
|
|
|
static bool SupportsVulkan()
|
|
{
|
|
// default to not supporting Vulkan
|
|
bool bSupportsVulkan = false;
|
|
GConfig->GetBool(TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"), TEXT("bSupportsVulkan"), bSupportsVulkan, GEngineIni);
|
|
|
|
// glslang library is needed for vulkan shader compiling
|
|
bool GlslangAvailable = false;
|
|
#if PLATFORM_WINDOWS
|
|
#if PLATFORM_64BITS
|
|
GlslangAvailable = true;
|
|
#endif
|
|
#elif PLATFORM_MAC
|
|
GlslangAvailable = false; // @TODO: change when glslang library compiled for Mac
|
|
#elif PLATFORM_LINUX
|
|
GlslangAvailable = false; // @TODO: change when glslang library compiled for Linux
|
|
#endif
|
|
|
|
return bSupportsVulkan && GlslangAvailable;
|
|
}
|
|
|
|
template<class TPlatformProperties>
|
|
inline FAndroidTargetPlatform<TPlatformProperties>::FAndroidTargetPlatform( ) :
|
|
DeviceDetection(nullptr)
|
|
{
|
|
#if WITH_ENGINE
|
|
FConfigCacheIni::LoadLocalIniFile(EngineSettings, TEXT("Engine"), true, *TTargetPlatformBase<TPlatformProperties>::PlatformName());
|
|
TextureLODSettings = nullptr; // These are registered by the device profile system.
|
|
StaticMeshLODSettings.Initialize(EngineSettings);
|
|
#endif
|
|
|
|
TickDelegate = FTickerDelegate::CreateRaw(this, &FAndroidTargetPlatform::HandleTicker);
|
|
TickDelegateHandle = FTicker::GetCoreTicker().AddTicker(TickDelegate, 4.0f);
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
inline FAndroidTargetPlatform<TPlatformProperties>::~FAndroidTargetPlatform()
|
|
{
|
|
FTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);
|
|
}
|
|
|
|
|
|
/* ITargetPlatform overrides
|
|
*****************************************************************************/
|
|
|
|
template<class TPlatformProperties>
|
|
inline void FAndroidTargetPlatform<TPlatformProperties>::GetAllDevices( TArray<ITargetDevicePtr>& OutDevices ) const
|
|
{
|
|
OutDevices.Reset();
|
|
|
|
for (auto Iter = Devices.CreateConstIterator(); Iter; ++Iter)
|
|
{
|
|
OutDevices.Add(Iter.Value());
|
|
}
|
|
}
|
|
|
|
template<class TPlatformProperties>
|
|
inline ECompressionFlags FAndroidTargetPlatform<TPlatformProperties>::GetBaseCompressionMethod( ) const
|
|
{
|
|
return COMPRESS_ZLIB;
|
|
}
|
|
|
|
template<class TPlatformProperties>
|
|
inline ITargetDevicePtr FAndroidTargetPlatform<TPlatformProperties>::GetDefaultDevice( ) const
|
|
{
|
|
// return the first device in the list
|
|
if (Devices.Num() > 0)
|
|
{
|
|
auto Iter = Devices.CreateConstIterator();
|
|
if (Iter)
|
|
{
|
|
return Iter.Value();
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
template<class TPlatformProperties>
|
|
inline ITargetDevicePtr FAndroidTargetPlatform<TPlatformProperties>::GetDevice( const FTargetDeviceId& DeviceId )
|
|
{
|
|
if (DeviceId.GetPlatformName() == TTargetPlatformBase<TPlatformProperties>::PlatformName())
|
|
{
|
|
return Devices.FindRef(DeviceId.GetDeviceName());
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
template<class TPlatformProperties>
|
|
inline bool FAndroidTargetPlatform<TPlatformProperties>::IsRunningPlatform( ) const
|
|
{
|
|
return false; // This platform never runs the target platform framework
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
inline bool FAndroidTargetPlatform<TPlatformProperties>::IsSdkInstalled(bool bProjectHasCode, FString& OutDocumentationPath) const
|
|
{
|
|
OutDocumentationPath = FString("Shared/Tutorials/SettingUpAndroidTutorial");
|
|
return true;
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
inline bool FAndroidTargetPlatform<TPlatformProperties>::SupportsFeature( ETargetPlatformFeatures Feature ) const
|
|
{
|
|
switch (Feature)
|
|
{
|
|
case ETargetPlatformFeatures::Packaging:
|
|
return true;
|
|
|
|
case ETargetPlatformFeatures::LowQualityLightmaps:
|
|
case ETargetPlatformFeatures::MobileRendering:
|
|
return SupportsES31() || SupportsES2() || SupportsVulkan();
|
|
|
|
case ETargetPlatformFeatures::HighQualityLightmaps:
|
|
case ETargetPlatformFeatures::Tessellation:
|
|
case ETargetPlatformFeatures::DeferredRendering:
|
|
return SupportsAEP();
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TTargetPlatformBase<TPlatformProperties>::SupportsFeature(Feature);
|
|
}
|
|
|
|
|
|
#if WITH_ENGINE
|
|
|
|
template<class TPlatformProperties>
|
|
inline void FAndroidTargetPlatform<TPlatformProperties>::GetAllPossibleShaderFormats( TArray<FName>& OutFormats ) const
|
|
{
|
|
static FName NAME_OPENGL_ES2(TEXT("GLSL_ES2"));
|
|
static FName NAME_GLSL_310_ES_EXT(TEXT("GLSL_310_ES_EXT"));
|
|
static FName NAME_SF_VULKAN_ES31_ANDROID(TEXT("SF_VULKAN_ES31_ANDROID"));
|
|
static FName NAME_GLSL_ES3_1_ANDROID(TEXT("GLSL_ES3_1_ANDROID"));
|
|
|
|
if (SupportsVulkan())
|
|
{
|
|
OutFormats.AddUnique(NAME_SF_VULKAN_ES31_ANDROID);
|
|
}
|
|
|
|
if (SupportsES2())
|
|
{
|
|
OutFormats.AddUnique(NAME_OPENGL_ES2);
|
|
}
|
|
|
|
if (SupportsES31())
|
|
{
|
|
OutFormats.AddUnique(NAME_GLSL_ES3_1_ANDROID);
|
|
}
|
|
|
|
if (SupportsAEP())
|
|
{
|
|
OutFormats.AddUnique(NAME_GLSL_310_ES_EXT);
|
|
}
|
|
}
|
|
|
|
template<class TPlatformProperties>
|
|
inline void FAndroidTargetPlatform<TPlatformProperties>::GetAllTargetedShaderFormats( TArray<FName>& OutFormats ) const
|
|
{
|
|
GetAllPossibleShaderFormats(OutFormats);
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
inline const FStaticMeshLODSettings& FAndroidTargetPlatform<TPlatformProperties>::GetStaticMeshLODSettings( ) const
|
|
{
|
|
return StaticMeshLODSettings;
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
inline void FAndroidTargetPlatform<TPlatformProperties>::GetTextureFormats( const UTexture* InTexture, TArray<FName>& OutFormats ) const
|
|
{
|
|
check(InTexture);
|
|
|
|
// The order we add texture formats to OutFormats is important. When multiple formats are cooked
|
|
// and supported by the device, the first supported format listed will be used.
|
|
// eg, ETC1/uncompressed should always be last
|
|
|
|
bool bNoCompression = InTexture->CompressionNone // Code wants the texture uncompressed.
|
|
|| (InTexture->LODGroup == TEXTUREGROUP_ColorLookupTable) // Textures in certain LOD groups should remain uncompressed.
|
|
|| (InTexture->LODGroup == TEXTUREGROUP_Bokeh)
|
|
|| (InTexture->CompressionSettings == TC_EditorIcon)
|
|
|| (InTexture->Source.GetSizeX() < 4) // Don't compress textures smaller than the DXT block size.
|
|
|| (InTexture->Source.GetSizeY() < 4)
|
|
|| (InTexture->Source.GetSizeX() % 4 != 0)
|
|
|| (InTexture->Source.GetSizeY() % 4 != 0);
|
|
|
|
bool bIsNonPOT = false;
|
|
#if WITH_EDITORONLY_DATA
|
|
// is this texture not a power of 2?
|
|
bIsNonPOT = !InTexture->Source.IsPowerOfTwo();
|
|
#endif
|
|
|
|
// Determine the pixel format of the compressed texture.
|
|
if (InTexture->LODGroup == TEXTUREGROUP_Shadowmap)
|
|
{
|
|
// forward rendering only needs one channel for shadow maps
|
|
OutFormats.Add(AndroidTexFormat::NameG8);
|
|
}
|
|
else if (bNoCompression && InTexture->HasHDRSource())
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameRGBA16F);
|
|
}
|
|
else if (bNoCompression)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameBGRA8);
|
|
}
|
|
else if (InTexture->CompressionSettings == TC_HDR
|
|
|| InTexture->CompressionSettings == TC_HDR_Compressed)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameRGBA16F);
|
|
}
|
|
else if (InTexture->CompressionSettings == TC_Normalmap)
|
|
{
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NamePVRTC4, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameDXT5, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameATC_RGBA_I, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC2, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC1, OutFormats, bIsNonPOT);
|
|
}
|
|
else if (InTexture->CompressionSettings == TC_Displacementmap)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameRGBA16F);
|
|
}
|
|
else if (InTexture->CompressionSettings == TC_VectorDisplacementmap)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameBGRA8);
|
|
}
|
|
else if (InTexture->CompressionSettings == TC_Grayscale)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameG8);
|
|
}
|
|
else if (InTexture->CompressionSettings == TC_Alpha)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameG8);
|
|
}
|
|
else if (InTexture->CompressionSettings == TC_DistanceFieldFont)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NameG8);
|
|
}
|
|
else if (InTexture->bForcePVRTC4
|
|
|| InTexture->CompressionSettings == TC_BC7)
|
|
{
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NamePVRTC4, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameDXT5, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameATC_RGBA_I, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC2, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC1, OutFormats, bIsNonPOT);
|
|
}
|
|
else if (InTexture->CompressionNoAlpha)
|
|
{
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NamePVRTC2, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameDXT1, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameATC_RGB, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameETC2_RGB, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameETC1, OutFormats, bIsNonPOT);
|
|
}
|
|
else if (InTexture->bDitherMipMapAlpha)
|
|
{
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NamePVRTC4, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameDXT5, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameATC_RGBA_I, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC2, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC1, OutFormats, bIsNonPOT);
|
|
}
|
|
else
|
|
{
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoPVRTC, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoDXT, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoATC, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC2, OutFormats, bIsNonPOT);
|
|
AddTextureFormatIfSupports(AndroidTexFormat::NameAutoETC1, OutFormats, bIsNonPOT);
|
|
}
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
void FAndroidTargetPlatform<TPlatformProperties>::GetReflectionCaptureFormats( TArray<FName>& OutFormats ) const
|
|
{
|
|
if (SupportsAEP())
|
|
{
|
|
// use Full HDR with AEP
|
|
OutFormats.Add(FName(TEXT("FullHDR")));
|
|
}
|
|
|
|
// always emit encoded
|
|
OutFormats.Add(FName(TEXT("EncodedHDR")));
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
const UTextureLODSettings& FAndroidTargetPlatform<TPlatformProperties>::GetTextureLODSettings() const
|
|
{
|
|
return *TextureLODSettings;
|
|
}
|
|
|
|
|
|
template<class TPlatformProperties>
|
|
FName FAndroidTargetPlatform<TPlatformProperties>::GetWaveFormat( const class USoundWave* Wave ) const
|
|
{
|
|
static bool formatRead = false;
|
|
static FName NAME_FORMAT;
|
|
|
|
if (!formatRead)
|
|
{
|
|
formatRead = true;
|
|
|
|
FString audioSetting;
|
|
if (!GConfig->GetString(TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings"), TEXT("AndroidAudio"), audioSetting, GEngineIni))
|
|
{
|
|
audioSetting = TEXT("DEFAULT");
|
|
}
|
|
|
|
#if WITH_OGGVORBIS
|
|
if (audioSetting == TEXT("OGG") || audioSetting == TEXT("Default"))
|
|
{
|
|
static FName NAME_OGG(TEXT("OGG"));
|
|
NAME_FORMAT = NAME_OGG;
|
|
}
|
|
#else
|
|
if (audioSetting == TEXT("OGG"))
|
|
{
|
|
UE_LOG(LogAudio, Error, TEXT("Attemped to select Ogg Vorbis encoding when the cooker is built without Ogg Vorbis support."));
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
|
|
// Otherwise return ADPCM as it'll either be option '2' or 'default' depending on WITH_OGGVORBIS config
|
|
static FName NAME_ADPCM(TEXT("ADPCM"));
|
|
NAME_FORMAT = NAME_ADPCM;
|
|
}
|
|
}
|
|
return NAME_FORMAT;
|
|
}
|
|
|
|
#endif //WITH_ENGINE
|
|
|
|
template<class TPlatformProperties>
|
|
bool FAndroidTargetPlatform<TPlatformProperties>::SupportsVariants() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template<class TPlatformProperties>
|
|
FText FAndroidTargetPlatform<TPlatformProperties>::GetVariantTitle() const
|
|
{
|
|
return LOCTEXT("AndroidVariantTitle", "Texture Format");
|
|
}
|
|
|
|
/* FAndroidTargetPlatform implementation
|
|
*****************************************************************************/
|
|
|
|
template<class TPlatformProperties>
|
|
inline void FAndroidTargetPlatform<TPlatformProperties>::AddTextureFormatIfSupports( FName Format, TArray<FName>& OutFormats, bool bIsCompressedNonPOT ) const
|
|
{
|
|
if (SupportsTextureFormat(Format))
|
|
{
|
|
if (bIsCompressedNonPOT && SupportsCompressedNonPOT() == false)
|
|
{
|
|
OutFormats.Add(AndroidTexFormat::NamePOTERROR);
|
|
}
|
|
else
|
|
{
|
|
OutFormats.Add(Format);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* FAndroidTargetPlatform callbacks
|
|
*****************************************************************************/
|
|
|
|
template<class TPlatformProperties>
|
|
inline bool FAndroidTargetPlatform<TPlatformProperties>::HandleTicker( float DeltaTime )
|
|
{
|
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_FAndroidTargetPlatform_HandleTicker);
|
|
|
|
if (DeviceDetection == nullptr)
|
|
{
|
|
DeviceDetection = FModuleManager::LoadModuleChecked<IAndroidDeviceDetectionModule>("AndroidDeviceDetection").GetAndroidDeviceDetection();
|
|
}
|
|
|
|
TArray<FString> ConnectedDeviceIds;
|
|
|
|
{
|
|
FScopeLock ScopeLock(DeviceDetection->GetDeviceMapLock());
|
|
|
|
auto DeviceIt = DeviceDetection->GetDeviceMap().CreateConstIterator();
|
|
|
|
for (; DeviceIt; ++DeviceIt)
|
|
{
|
|
ConnectedDeviceIds.Add(DeviceIt.Key());
|
|
|
|
const FAndroidDeviceInfo& DeviceInfo = DeviceIt.Value();
|
|
|
|
// see if this device is already known
|
|
if (Devices.Contains(DeviceIt.Key()))
|
|
{
|
|
//still update its authorized status, which could change while connected
|
|
Devices[DeviceIt.Key()]->SetAuthorized(DeviceInfo.bAuthorizedDevice);
|
|
continue;
|
|
}
|
|
|
|
// check if this platform is supported by the extensions and version
|
|
if (!SupportedByExtensionsString(DeviceInfo.GLESExtensions, DeviceInfo.GLESVersion))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// create target device
|
|
FAndroidTargetDevicePtr& Device = Devices.Add(DeviceInfo.SerialNumber);
|
|
|
|
Device = MakeShareable(new FAndroidTargetDevice(*this, DeviceInfo.SerialNumber, GetAndroidVariantName()));
|
|
|
|
Device->SetConnected(true);
|
|
Device->SetModel(DeviceInfo.Model);
|
|
Device->SetDeviceName(DeviceInfo.DeviceName);
|
|
Device->SetAuthorized(DeviceInfo.bAuthorizedDevice);
|
|
Device->SetVersions(DeviceInfo.SDKVersion, DeviceInfo.HumanAndroidVersion);
|
|
|
|
DeviceDiscoveredEvent.Broadcast(Device.ToSharedRef());
|
|
}
|
|
}
|
|
|
|
// remove disconnected devices
|
|
for (auto Iter = Devices.CreateIterator(); Iter; ++Iter)
|
|
{
|
|
if (!ConnectedDeviceIds.Contains(Iter.Key()))
|
|
{
|
|
FAndroidTargetDevicePtr RemovedDevice = Iter.Value();
|
|
RemovedDevice->SetConnected(false);
|
|
|
|
Iter.RemoveCurrent();
|
|
|
|
DeviceLostEvent.Broadcast(RemovedDevice.ToSharedRef());
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|