/** * @file * * @author Mamadou Babaei * * @section LICENSE * * (The MIT License) * * Copyright (c) 2020 - 2025 SenseGlove * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * @section DESCRIPTION * * */ #include "SGAndroid/SGAndroidPermissions.h" #include "AndroidPermissionCallbackProxy.h" #include "AndroidPermissionFunctionLibrary.h" #include "Engine/Engine.h" #include "SGLog/SGLog.h" struct USGAndroidPermissions::FImpl { /************************ * Member variables ************************/ TFunction&, const TArray&)> PermissionsGrantedCallback; /************************ * Owner object ************************/ USGAndroidPermissions* Owner; /************************ * Constructor / Destructor ************************/ explicit FImpl(USGAndroidPermissions* InOwner); ~FImpl(); /************************ * Default copy constructor & copy assignment operator ************************/ FImpl(const FImpl& Rhs) = default; FImpl& operator=(const FImpl& Rhs) = default; }; USGAndroidPermissions* USGAndroidPermissions::GetInstance() { if (!ensureAlwaysMsgf(GEngine, TEXT("The engine has not been initialized!"))) { return nullptr; } USGAndroidPermissions* Instance{GEngine->GetEngineSubsystem()}; return Instance; } USGAndroidPermissions::USGAndroidPermissions() : Pimpl(TUniquePtr(new FImpl{this}, PimplDeleter)) { } void USGAndroidPermissions::Request( const TFunction&, const TArray&)>& PermissionsGrantedCallback) { TArray Permissions{ "android.permission.ACCESS_BACKGROUND_LOCATION", "android.permission.ACCESS_FINE_LOCATION", "android.permission.BLUETOOTH", "android.permission.BLUETOOTH_ADMIN", "android.permission.BLUETOOTH_ADVERTISE", "android.permission.BLUETOOTH_CONNECT", "android.permission.BLUETOOTH_SCAN", }; bool bHasAllRequiredPermissions = false; for (const FString& Permission: Permissions) { const bool bHasPermission = UAndroidPermissionFunctionLibrary::CheckPermission(Permission); bHasAllRequiredPermissions = bHasPermission; if (!bHasAllRequiredPermissions) { break; } } if (!bHasAllRequiredPermissions) { Pimpl->PermissionsGrantedCallback = PermissionsGrantedCallback; UAndroidPermissionFunctionLibrary::AcquirePermissions( MoveTemp(Permissions))->OnPermissionsGrantedDelegate.AddUObject( this, &USGAndroidPermissions::OnPermissionsGranted); } else { TArray GrantedResults; for (int32 i = 0; i < Permissions.Num(); ++i) { GrantedResults.Add(true); } PermissionsGrantedCallback(MoveTemp(Permissions), MoveTemp(GrantedResults)); } } void USGAndroidPermissions::OnPermissionsGranted(const TArray& Permissions, const TArray& GrantResults) { if (!ensureAlwaysMsgf(Permissions.Num() == GrantResults.Num(), TEXT("Mismatched number of Permissions and GrantedResults!"))) { return; } for (int32 i = 0; i < Permissions.Num(); ++i) { if (GrantResults[i]) { SGLOG("Permission Granted", Permissions[i]); } else { SGLOG("Permission Denied", Permissions[i]); } } Pimpl->PermissionsGrantedCallback(Permissions, GrantResults); } bool USGAndroidPermissions::ShouldCreateSubsystem(UObject* Outer) const { return true; } void USGAndroidPermissions::Initialize(FSubsystemCollectionBase& Collection) { SGLOG("Initializing the SenseGlove Android permissions singleton with the engine lifetime..."); Super::Initialize(Collection); SGLOG("The SenseGlove Android permissions singleton has been successfully initialized with the engine lifetime!"); } void USGAndroidPermissions::Deinitialize() { SGLOG("De-initializing the SenseGlove Android permissions singleton due to the engine lifetime expiration..."); Super::Deinitialize(); (void) Pimpl.Release(); SGLOG("The SenseGlove Android permissions singleton has been successfully de-initialized!"); } USGAndroidPermissions::FImpl::FImpl(USGAndroidPermissions* InOwner) : Owner(InOwner) { } USGAndroidPermissions::FImpl::~FImpl() = default; void USGAndroidPermissions::FImplDeleter::operator()(const FImpl* P) const { delete P; }