diff --git a/Assets/Plugins/Android/AndroidManifest.xml b/Assets/Plugins/Android/AndroidManifest.xml
index fd52ce5206..8b803d7168 100644
--- a/Assets/Plugins/Android/AndroidManifest.xml
+++ b/Assets/Plugins/Android/AndroidManifest.xml
@@ -18,4 +18,5 @@
+
diff --git a/Assets/Scenes/Loading.unity b/Assets/Scenes/Loading.unity
index bfeffc32f9..3118b0fd1d 100644
--- a/Assets/Scenes/Loading.unity
+++ b/Assets/Scenes/Loading.unity
@@ -206,6 +206,27 @@ MonoBehaviour:
m_VrCamera: {fileID: 1815664868}
m_MaximumLoadingTime: 60
m_SceneLoadRatio: 0.75
+ m_LoadingText:
+ m_TableReference:
+ m_TableCollectionName: GUID:c84355079ab3f3e4f8f3812258805f86
+ m_TableEntryReference:
+ m_KeyId: 287897575133184
+ m_Key:
+ m_FallbackState: 0
+ m_WaitForCompletion: 0
+ m_LocalVariables: []
+ m_RequestAndroidFolderPermissions:
+ m_TableReference:
+ m_TableCollectionName: GUID:c84355079ab3f3e4f8f3812258805f86
+ m_TableEntryReference:
+ m_KeyId: 170004956477833216
+ m_Key:
+ m_FallbackState: 0
+ m_WaitForCompletion: 0
+ m_LocalVariables: []
+ references:
+ version: 2
+ RefIds: []
--- !u!4 &326031496
Transform:
m_ObjectHideFlags: 0
diff --git a/Assets/Scripts/LoadingScene.cs b/Assets/Scripts/LoadingScene.cs
index 46afef83d2..491401df6b 100644
--- a/Assets/Scripts/LoadingScene.cs
+++ b/Assets/Scripts/LoadingScene.cs
@@ -15,6 +15,11 @@
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
+using UnityEngine.Localization;
+
+#if UNITY_ANDROID
+using UnityEngine.Android;
+#endif
namespace TiltBrush
{
@@ -27,11 +32,17 @@ public class LoadingScene : MonoBehaviour
// Amount of the progress bar taken up by the scene load
[SerializeField] private float m_SceneLoadRatio;
+ [SerializeField] private LocalizedString m_LoadingText;
+ [SerializeField] private LocalizedString m_RequestAndroidFolderPermissions;
+
// We have a slightly faked loading position that will always increase
// The fake loading rate is the minimum amount it will increase in one second, the reciprocal of
// m_MaximumLoadingTime
private float m_FakeLoadingRate;
private float m_CurrentLoadingPosition;
+#if UNITY_ANDROID
+ private bool m_FolderPermissionOverride = false;
+#endif
private IEnumerator Start()
{
@@ -58,6 +69,23 @@ private IEnumerator Start()
DontDestroyOnLoad(gameObject);
+#if UNITY_ANDROID
+ if (Application.platform == RuntimePlatform.Android)
+ {
+ if (!UserHasManageExternalStoragePermission())
+ {
+ m_Overlay.MessageStatus = m_RequestAndroidFolderPermissions.GetLocalizedString();
+ AskForManageStoragePermission();
+ while (!UserHasManageExternalStoragePermission())
+ {
+ yield return new WaitForEndOfFrame();
+ }
+
+ m_Overlay.MessageStatus = m_LoadingText.GetLocalizedString();
+ }
+ }
+#endif
+
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("Main");
while (!asyncLoad.isDone)
{
@@ -91,5 +119,45 @@ private void UpdateProgress(float start, float scale, float progress)
m_CurrentLoadingPosition = Mathf.Max(m_CurrentLoadingPosition, position);
m_Overlay.Progress = m_CurrentLoadingPosition;
}
+
+#if UNITY_ANDROID
+ private bool UserHasManageExternalStoragePermission()
+ {
+ bool isExternalStorageManager = false;
+ try
+ {
+ AndroidJavaClass environmentClass = new AndroidJavaClass("android.os.Environment");
+ isExternalStorageManager = environmentClass.CallStatic("isExternalStorageManager");
+ }
+ catch (AndroidJavaException e)
+ {
+ Debug.LogError("Java Exception caught and ignored: " + e.Message);
+ Debug.LogError("Assuming this means this device doesn't support isExternalStorageManager.");
+ }
+ return m_FolderPermissionOverride || isExternalStorageManager;
+ }
+
+ private void AskForManageStoragePermission()
+ {
+ try
+ {
+ using var unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
+ using AndroidJavaObject currentActivityObject = unityClass.GetStatic("currentActivity");
+ string packageName = currentActivityObject.Call("getPackageName");
+ using var uriClass = new AndroidJavaClass("android.net.Uri");
+ using AndroidJavaObject uriObject = uriClass.CallStatic("fromParts", "package", packageName, null);
+ using var intentObject = new AndroidJavaObject("android.content.Intent", "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION", uriObject);
+ intentObject.Call("addCategory", "android.intent.category.DEFAULT");
+ currentActivityObject.Call("startActivity", intentObject);
+ }
+ catch (AndroidJavaException e)
+ {
+ // TODO: only skip this if it's of type act=android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
+ m_FolderPermissionOverride = true;
+ Debug.LogError("Java Exception caught and ignored: " + e.Message);
+ Debug.LogError("Assuming this means we don't need android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION (e.g., Android SDK < 30)");
+ }
+ }
+#endif
}
} // namespace TiltBrush
diff --git a/Assets/Settings/Localization/Strings/Strings Shared Data.asset b/Assets/Settings/Localization/Strings/Strings Shared Data.asset
index 7668047cbb..bcb1066875 100644
--- a/Assets/Settings/Localization/Strings/Strings Shared Data.asset
+++ b/Assets/Settings/Localization/Strings/Strings Shared Data.asset
@@ -540,7 +540,7 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 287897575133184
- m_Key: LOADING_SCENE_OVERLAY_MESSAGE
+ m_Key: LOADING_SCENE_OVERLAY_LOADING
m_Metadata:
m_Items: []
- m_Id: 7892854560759808
@@ -3271,6 +3271,10 @@ MonoBehaviour:
m_Key: POPUP_RECORD_UNSUPPORTED_TEXT
m_Metadata:
m_Items: []
+ - m_Id: 170004956477833216
+ m_Key: LOADING_SCENE_OVERLAY_ANDROIDPERMISSIONS
+ m_Metadata:
+ m_Items: []
m_Metadata:
m_Items: []
m_KeyGenerator:
diff --git a/Assets/Settings/Localization/Strings/Strings_en.asset b/Assets/Settings/Localization/Strings/Strings_en.asset
index 3095eb46f3..c46cc808e2 100644
--- a/Assets/Settings/Localization/Strings/Strings_en.asset
+++ b/Assets/Settings/Localization/Strings/Strings_en.asset
@@ -3101,7 +3101,7 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 106429517453328384
- m_Localized: "Background Images"
+ m_Localized: Background Images
m_Metadata:
m_Items: []
- m_Id: 95221400803737600
@@ -3457,11 +3457,15 @@ MonoBehaviour:
m_Metadata:
m_Items: []
- m_Id: 151490030713540608
- m_Localized: 'You can create a video of your sketch by opening it on a Mac or PC.
- Search for "Exporting video" on our docs website: https://docs.openbrush.app
+ m_Localized: 'You can create a video of your sketch by opening it on a Mac or
+ PC. Search for "Exporting video" on our docs website: https://docs.openbrush.app
for a step by step guide.'
m_Metadata:
m_Items: []
+ - m_Id: 170004956477833216
+ m_Localized: Please give Open Brush file access to save your creations!
+ m_Metadata:
+ m_Items: []
references:
version: 2
RefIds: []
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index d6545b629e..c24ca29363 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -175,8 +175,8 @@ PlayerSettings:
tvOS: 0
overrideDefaultApplicationIdentifier: 1
AndroidBundleVersionCode: 1
- AndroidMinSdkVersion: 27
- AndroidTargetSdkVersion: 29
+ AndroidMinSdkVersion: 29
+ AndroidTargetSdkVersion: 32
AndroidPreferredInstallLocation: 0
aotOptions:
stripEngineCode: 1