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 2958982 on 2016/04/28 by Dmitriy.Dyomin Set owner name for RHI texture, for easier debugging Change 2976446 on 2016/05/12 by Niklas.Smedberg Fixed Device Profile CVars so they work even if a DLL with the cvar definition is loaded afterwards. (And they now also go through the common code path for CVars.) Change 2983781 on 2016/05/19 by Steve.Cano Check in PlayUsingLauncher if the device we're launching to is authorized by the computer. Could not get to this information about Devices so added an IsAuthorized interface to ITargetDevice that is overriden in the AndroidTargetDevice. Also make sure to referesh the authorized state as needed for Android device detection. Finally, changed the name of the authorized variable to be more readable (true == authorized instead of true == unauthorized) #jira UE-21121 #ue4 #android Change 2994202 on 2016/05/31 by Allan.Bentham Prevent clear transulcency volume null deref crash. Change test for allocated deferred render targets by testing against an exclusively deferred target (instead of potentially shared shadow depth surface) probable fix for UE-22073 Change 2995613 on 2016/05/31 by Dmitriy.Dyomin Added: Option to force full precision in a material UEMOB-109 Change 2997960 on 2016/06/02 by Gareth.Martin Refactored Landscape serialization to allow cooking both the data used for normal rendering and mobile rendering into the same package #jira UE-31474 Change 2997988 on 2016/06/02 by Gareth.Martin Files missing from CL 2997960 #jira UE-31474 Change 2999222 on 2016/06/03 by Jack.Porter Fix up ETargetPlatformFeatures::ForwardRendering and ETargetPlatformFeatures::DeferredRendering for iOS to support the Metal MRT deferred renderer Change 2999229 on 2016/06/03 by Jack.Porter Rename ETargetPlatformFeatures::ForwardRendering to TargetPlatformFeatures::MobileRendering Change 3003540 on 2016/06/07 by Jack.Porter Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile) Change 3003779 on 2016/06/07 by Dmitriy.Dyomin Fixed: Criss-crossed sublevels cause NavMesh errors #jira UE-27157 Change 3004535 on 2016/06/07 by Steve.Cano Adding the OnControllerConnectionChange delegate message when a controller is connected on Android. Also added additional future broadcast statement when disconnect support is added for Android. #jira UE-25697 #ue4 #android Change 3005205 on 2016/06/07 by Niklas.Smedberg Bumped ASTC format version to invalidate bad server DDC Change 3005347 on 2016/06/08 by Dmitriy.Dyomin Added a way to cache OpenGL program binaries on the disk. Disabled by default. Can be enabled only on Android platform (r.UseProgramBinaryCache=1) #jira UEMOB-108 Change 3005524 on 2016/06/08 by Dmitriy.Dyomin Fixed iOS build broken by CL# 3005347 Change 3005528 on 2016/06/08 by Jack.Porter Changed hardcoded checkboxes from quality level overrides dialog to use the general property details code. Now magically supports any uproperty types such as enums or integers added to FMaterialQualityOverrides. Change 3005607 on 2016/06/08 by Dmitriy.Dyomin Fixed: Occasional crash on using Launch on Android device when device is being disconnected Change 3006705 on 2016/06/08 by Chris.Babcock Fix virtual joystick to return -1 to 1 ranges for thumbsticks #jira UE-31799 #ue4 #android #ios Change 3006960 on 2016/06/08 by Jack.Porter Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile) Change 3007050 on 2016/06/09 by Jack.Porter FAutomationWorkerModule::ReportTestComplete() needs to send analytics first as the message endpoint will free the memory resulting in a crash Change 3007129 on 2016/06/09 by Dmitriy.Dyomin Fixed: Black edges seen on flames in Sun Temple #jira UE-31712 Change 3010686 on 2016/06/13 by Dmitriy.Dyomin Fixed: Android Monolithic warnings for glGetProgramBinaryOES and glProgramBinaryOES #jira UE-31933 [CL 3011074 by Jack Porter in Main branch]
427 lines
12 KiB
C++
427 lines
12 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
AndroidDeviceDetectionModule.cpp: Implements the FAndroidDeviceDetectionModule class.
|
|
=============================================================================*/
|
|
|
|
#include "AndroidDeviceDetectionPrivatePCH.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "FAndroidDeviceDetectionModule"
|
|
|
|
DEFINE_LOG_CATEGORY_STATIC(AndroidDeviceDetectionLog, Log, All);
|
|
|
|
class FAndroidDeviceDetectionRunnable : public FRunnable
|
|
{
|
|
public:
|
|
FAndroidDeviceDetectionRunnable(TMap<FString,FAndroidDeviceInfo>& InDeviceMap, FCriticalSection* InDeviceMapLock, FCriticalSection* InADBPathCheckLock) :
|
|
StopTaskCounter(0),
|
|
DeviceMap(InDeviceMap),
|
|
DeviceMapLock(InDeviceMapLock),
|
|
ADBPathCheckLock(InADBPathCheckLock),
|
|
HasADBPath(false),
|
|
ForceCheck(false)
|
|
|
|
{
|
|
}
|
|
|
|
public:
|
|
|
|
// FRunnable interface.
|
|
virtual bool Init(void)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
virtual void Exit(void)
|
|
{
|
|
}
|
|
|
|
virtual void Stop(void)
|
|
{
|
|
StopTaskCounter.Increment();
|
|
}
|
|
|
|
virtual uint32 Run(void)
|
|
{
|
|
int LoopCount = 10;
|
|
|
|
while (StopTaskCounter.GetValue() == 0)
|
|
{
|
|
// query every 10 seconds
|
|
if (LoopCount++ >= 10 || ForceCheck)
|
|
{
|
|
// Make sure we have an ADB path before checking
|
|
FScopeLock PathLock(ADBPathCheckLock);
|
|
if (HasADBPath)
|
|
QueryConnectedDevices();
|
|
|
|
LoopCount = 0;
|
|
ForceCheck = false;
|
|
}
|
|
|
|
FPlatformProcess::Sleep(1.0f);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void UpdateADBPath(FString &InADBPath)
|
|
{
|
|
ADBPath = InADBPath;
|
|
HasADBPath = !ADBPath.IsEmpty();
|
|
// Force a check next time we go around otherwise it can take over 10sec to find devices
|
|
ForceCheck = HasADBPath;
|
|
|
|
// If we have no path then clean the existing devices out
|
|
if (!HasADBPath && DeviceMap.Num() > 0)
|
|
{
|
|
DeviceMap.Reset();
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
bool ExecuteAdbCommand( const FString& CommandLine, FString* OutStdOut, FString* OutStdErr ) const
|
|
{
|
|
// execute the command
|
|
int32 ReturnCode;
|
|
FString DefaultError;
|
|
|
|
// make sure there's a place for error output to go if the caller specified nullptr
|
|
if (!OutStdErr)
|
|
{
|
|
OutStdErr = &DefaultError;
|
|
}
|
|
|
|
FPlatformProcess::ExecProcess(*ADBPath, *CommandLine, &ReturnCode, OutStdOut, OutStdErr);
|
|
|
|
if (ReturnCode != 0)
|
|
{
|
|
FPlatformMisc::LowLevelOutputDebugStringf(TEXT("The Android SDK command '%s' failed to run. Return code: %d, Error: %s\n"), *CommandLine, ReturnCode, **OutStdErr);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void QueryConnectedDevices()
|
|
{
|
|
// grab the list of devices via adb
|
|
FString StdOut;
|
|
if (!ExecuteAdbCommand(TEXT("devices -l"), &StdOut, nullptr))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// separate out each line
|
|
TArray<FString> DeviceStrings;
|
|
StdOut = StdOut.Replace(TEXT("\r"), TEXT("\n"));
|
|
StdOut.ParseIntoArray(DeviceStrings, TEXT("\n"), true);
|
|
|
|
// a list containing all devices found this time, so we can remove anything not in this list
|
|
TArray<FString> CurrentlyConnectedDevices;
|
|
|
|
for (int32 StringIndex = 0; StringIndex < DeviceStrings.Num(); ++StringIndex)
|
|
{
|
|
const FString& DeviceString = DeviceStrings[StringIndex];
|
|
|
|
// skip over non-device lines
|
|
if (DeviceString.StartsWith("* ") || DeviceString.StartsWith("List "))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// grab the device serial number
|
|
int32 TabIndex;
|
|
|
|
// use either tab or space as separator
|
|
if (!DeviceString.FindChar(TCHAR('\t'), TabIndex))
|
|
{
|
|
if (!DeviceString.FindChar(TCHAR(' '), TabIndex))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
FAndroidDeviceInfo NewDeviceInfo;
|
|
|
|
NewDeviceInfo.SerialNumber = DeviceString.Left(TabIndex);
|
|
const FString DeviceState = DeviceString.Mid(TabIndex + 1).Trim();
|
|
|
|
NewDeviceInfo.bAuthorizedDevice = DeviceState != TEXT("unauthorized");
|
|
|
|
// add it to our list of currently connected devices
|
|
CurrentlyConnectedDevices.Add(NewDeviceInfo.SerialNumber);
|
|
|
|
// move on to next device if this one is already a known device that has either already been authorized or the authorization
|
|
// status has not changed
|
|
if (DeviceMap.Contains(NewDeviceInfo.SerialNumber) &&
|
|
(DeviceMap[NewDeviceInfo.SerialNumber].bAuthorizedDevice || !NewDeviceInfo.bAuthorizedDevice))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!NewDeviceInfo.bAuthorizedDevice)
|
|
{
|
|
//note: AndroidTargetDevice::GetName() does not fetch this value, do not rely on this
|
|
NewDeviceInfo.DeviceName = TEXT("Unauthorized - enable USB debugging");
|
|
}
|
|
else
|
|
{
|
|
// grab the Android version
|
|
const FString AndroidVersionCommand = FString::Printf(TEXT("-s %s shell getprop ro.build.version.release"), *NewDeviceInfo.SerialNumber);
|
|
if (!ExecuteAdbCommand(*AndroidVersionCommand, &NewDeviceInfo.HumanAndroidVersion, nullptr))
|
|
{
|
|
continue;
|
|
}
|
|
NewDeviceInfo.HumanAndroidVersion = NewDeviceInfo.HumanAndroidVersion.Replace(TEXT("\r"), TEXT("")).Replace(TEXT("\n"), TEXT(""));
|
|
NewDeviceInfo.HumanAndroidVersion.Trim().TrimTrailing();
|
|
|
|
// grab the Android SDK version
|
|
const FString SDKVersionCommand = FString::Printf(TEXT("-s %s shell getprop ro.build.version.sdk"), *NewDeviceInfo.SerialNumber);
|
|
FString SDKVersionString;
|
|
if (!ExecuteAdbCommand(*SDKVersionCommand, &SDKVersionString, nullptr))
|
|
{
|
|
continue;
|
|
}
|
|
NewDeviceInfo.SDKVersion = FCString::Atoi(*SDKVersionString);
|
|
if (NewDeviceInfo.SDKVersion <= 0)
|
|
{
|
|
NewDeviceInfo.SDKVersion = INDEX_NONE;
|
|
}
|
|
|
|
// get the GL extensions string (and a bunch of other stuff)
|
|
const FString ExtensionsCommand = FString::Printf(TEXT("-s %s shell dumpsys SurfaceFlinger"), *NewDeviceInfo.SerialNumber);
|
|
if (!ExecuteAdbCommand(*ExtensionsCommand, &NewDeviceInfo.GLESExtensions, nullptr))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// grab the GL ES version
|
|
FString GLESVersionString;
|
|
const FString GLVersionCommand = FString::Printf(TEXT("-s %s shell getprop ro.opengles.version"), *NewDeviceInfo.SerialNumber);
|
|
if (!ExecuteAdbCommand(*GLVersionCommand, &GLESVersionString, nullptr))
|
|
{
|
|
continue;
|
|
}
|
|
NewDeviceInfo.GLESVersion = FCString::Atoi(*GLESVersionString);
|
|
|
|
// parse the device model
|
|
FParse::Value(*DeviceString, TEXT("model:"), NewDeviceInfo.Model);
|
|
if (NewDeviceInfo.Model.IsEmpty())
|
|
{
|
|
FString ModelCommand = FString::Printf(TEXT("-s %s shell getprop ro.product.model"), *NewDeviceInfo.SerialNumber);
|
|
FString RoProductModel;
|
|
ExecuteAdbCommand(*ModelCommand, &RoProductModel, nullptr);
|
|
const TCHAR* Ptr = *RoProductModel;
|
|
FParse::Line(&Ptr, NewDeviceInfo.Model);
|
|
}
|
|
|
|
// parse the device name
|
|
FParse::Value(*DeviceString, TEXT("device:"), NewDeviceInfo.DeviceName);
|
|
if (NewDeviceInfo.DeviceName.IsEmpty())
|
|
{
|
|
FString DeviceCommand = FString::Printf(TEXT("-s %s shell getprop ro.product.device"), *NewDeviceInfo.SerialNumber);
|
|
FString RoProductDevice;
|
|
ExecuteAdbCommand(*DeviceCommand, &RoProductDevice, nullptr);
|
|
const TCHAR* Ptr = *RoProductDevice;
|
|
FParse::Line(&Ptr, NewDeviceInfo.DeviceName);
|
|
}
|
|
}
|
|
|
|
// add the device to the map
|
|
{
|
|
FScopeLock ScopeLock(DeviceMapLock);
|
|
|
|
FAndroidDeviceInfo& SavedDeviceInfo = DeviceMap.Add(NewDeviceInfo.SerialNumber);
|
|
SavedDeviceInfo = NewDeviceInfo;
|
|
}
|
|
}
|
|
|
|
// loop through the previously connected devices list and remove any that aren't still connected from the updated DeviceMap
|
|
TArray<FString> DevicesToRemove;
|
|
|
|
for (auto It = DeviceMap.CreateConstIterator(); It; ++It)
|
|
{
|
|
if (!CurrentlyConnectedDevices.Contains(It.Key()))
|
|
{
|
|
DevicesToRemove.Add(It.Key());
|
|
}
|
|
}
|
|
|
|
{
|
|
// enter the critical section and remove the devices from the map
|
|
FScopeLock ScopeLock(DeviceMapLock);
|
|
|
|
for (auto It = DevicesToRemove.CreateConstIterator(); It; ++It)
|
|
{
|
|
DeviceMap.Remove(*It);
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
// path to the adb command
|
|
FString ADBPath;
|
|
|
|
// > 0 if we've been asked to abort work in progress at the next opportunity
|
|
FThreadSafeCounter StopTaskCounter;
|
|
|
|
TMap<FString,FAndroidDeviceInfo>& DeviceMap;
|
|
FCriticalSection* DeviceMapLock;
|
|
|
|
FCriticalSection* ADBPathCheckLock;
|
|
bool HasADBPath;
|
|
bool ForceCheck;
|
|
};
|
|
|
|
class FAndroidDeviceDetection : public IAndroidDeviceDetection
|
|
{
|
|
public:
|
|
|
|
FAndroidDeviceDetection() :
|
|
DetectionThread(nullptr),
|
|
DetectionThreadRunnable(nullptr)
|
|
{
|
|
// create and fire off our device detection thread
|
|
DetectionThreadRunnable = new FAndroidDeviceDetectionRunnable(DeviceMap, &DeviceMapLock, &ADBPathCheckLock);
|
|
DetectionThread = FRunnableThread::Create(DetectionThreadRunnable, TEXT("FAndroidDeviceDetectionRunnable"));
|
|
|
|
// get the SDK binaries folder and throw it to the runnable
|
|
UpdateADBPath();
|
|
}
|
|
|
|
virtual ~FAndroidDeviceDetection()
|
|
{
|
|
if (DetectionThreadRunnable && DetectionThread)
|
|
{
|
|
DetectionThreadRunnable->Stop();
|
|
DetectionThread->WaitForCompletion();
|
|
}
|
|
}
|
|
|
|
virtual const TMap<FString,FAndroidDeviceInfo>& GetDeviceMap() override
|
|
{
|
|
return DeviceMap;
|
|
}
|
|
|
|
virtual FCriticalSection* GetDeviceMapLock() override
|
|
{
|
|
return &DeviceMapLock;
|
|
}
|
|
|
|
virtual void UpdateADBPath() override
|
|
{
|
|
FScopeLock PathUpdateLock(&ADBPathCheckLock);
|
|
TCHAR AndroidDirectory[32768] = { 0 };
|
|
FPlatformMisc::GetEnvironmentVariable(TEXT("ANDROID_HOME"), AndroidDirectory, 32768);
|
|
|
|
FString ADBPath;
|
|
|
|
#if PLATFORM_MAC
|
|
if (AndroidDirectory[0] == 0)
|
|
{
|
|
// didn't find ANDROID_HOME, so parse the .bash_profile file on MAC
|
|
FArchive* FileReader = IFileManager::Get().CreateFileReader(*FString([@"~/.bash_profile" stringByExpandingTildeInPath]));
|
|
if (FileReader)
|
|
{
|
|
const int64 FileSize = FileReader->TotalSize();
|
|
ANSICHAR* AnsiContents = (ANSICHAR*)FMemory::Malloc(FileSize + 1);
|
|
FileReader->Serialize(AnsiContents, FileSize);
|
|
FileReader->Close();
|
|
delete FileReader;
|
|
|
|
AnsiContents[FileSize] = 0;
|
|
TArray<FString> Lines;
|
|
FString(ANSI_TO_TCHAR(AnsiContents)).ParseIntoArrayLines(Lines);
|
|
FMemory::Free(AnsiContents);
|
|
|
|
for (int32 Index = Lines.Num()-1; Index >=0; Index--)
|
|
{
|
|
if (AndroidDirectory[0] == 0 && Lines[Index].StartsWith(TEXT("export ANDROID_HOME=")))
|
|
{
|
|
FString Directory;
|
|
Lines[Index].Split(TEXT("="), NULL, &Directory);
|
|
Directory = Directory.Replace(TEXT("\""), TEXT(""));
|
|
FCString::Strcpy(AndroidDirectory, *Directory);
|
|
setenv("ANDROID_HOME", TCHAR_TO_ANSI(AndroidDirectory), 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (AndroidDirectory[0] != 0)
|
|
{
|
|
#if PLATFORM_WINDOWS
|
|
ADBPath = FString::Printf(TEXT("%s\\platform-tools\\adb.exe"), AndroidDirectory);
|
|
#else
|
|
ADBPath = FString::Printf(TEXT("%s/platform-tools/adb"), AndroidDirectory);
|
|
#endif
|
|
|
|
// if it doesn't exist then just clear the path as we might set it later
|
|
if (!FPaths::FileExists(*ADBPath))
|
|
{
|
|
ADBPath.Empty();
|
|
}
|
|
}
|
|
DetectionThreadRunnable->UpdateADBPath(ADBPath);
|
|
}
|
|
|
|
private:
|
|
|
|
|
|
FRunnableThread* DetectionThread;
|
|
FAndroidDeviceDetectionRunnable* DetectionThreadRunnable;
|
|
|
|
TMap<FString,FAndroidDeviceInfo> DeviceMap;
|
|
FCriticalSection DeviceMapLock;
|
|
FCriticalSection ADBPathCheckLock;
|
|
};
|
|
|
|
|
|
/**
|
|
* Holds the target platform singleton.
|
|
*/
|
|
static FAndroidDeviceDetection* AndroidDeviceDetectionSingleton = nullptr;
|
|
|
|
|
|
/**
|
|
* Module for detecting android devices.
|
|
*/
|
|
class FAndroidDeviceDetectionModule : public IAndroidDeviceDetectionModule
|
|
{
|
|
public:
|
|
|
|
/**
|
|
* Destructor.
|
|
*/
|
|
~FAndroidDeviceDetectionModule( )
|
|
{
|
|
if (AndroidDeviceDetectionSingleton != nullptr)
|
|
{
|
|
delete AndroidDeviceDetectionSingleton;
|
|
}
|
|
|
|
AndroidDeviceDetectionSingleton = nullptr;
|
|
}
|
|
|
|
virtual IAndroidDeviceDetection* GetAndroidDeviceDetection() override
|
|
{
|
|
if (AndroidDeviceDetectionSingleton == nullptr)
|
|
{
|
|
AndroidDeviceDetectionSingleton = new FAndroidDeviceDetection();
|
|
}
|
|
|
|
return AndroidDeviceDetectionSingleton;
|
|
}
|
|
};
|
|
|
|
|
|
#undef LOCTEXT_NAMESPACE
|
|
|
|
|
|
IMPLEMENT_MODULE( FAndroidDeviceDetectionModule, AndroidDeviceDetection);
|