Forum Discussion

🚨 This forum is archived and read-only. To submit a forum post, please visit our new Developer Forum. 🚨
Florian.BRINK's avatar
4 years ago
Solved

Save a PNG to /sdcard/Oculus/Screenshots on Quest 2

So we're trying to figure out how to save images to the "Screenshots" Oculus folder on Quest 2. Android won't ever let us write anywhere else than in the Application.persistentDataPath folder using F...
  • whitebozo's avatar
    4 years ago

    EDIT: Found a WAY Better solution for this it saves it to the gallery and doesn't need a restart to pop up. Also just a note Oculus won't let you on the store/out of app lab with the Permissions I listed below which this new method avoids completely.

     

    So First off no need for any changes to your manifest.

     

    Secondly you will need to write a function to take advantage of Androids MediaStore capabilities. Luckily there was a very helpful Unity Answers that helped me with this part.

     

    Here is the code for Saving the screenshot, I made an AndroidExtensions class to hold it all.

     

        public class AndroidExtensions
        {
            private static AndroidJavaObject _activity;
    
            private static AndroidJavaObject Activity
            {
                get
                {
                    if (_activity != null) return _activity;
                    var unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
                    _activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
                    return _activity;
                }
            }
            
            private const string MediaStoreImagesMediaClass = "android.provider.MediaStore$Images$Media";
            
            public static string SaveImageToGallery(Texture2D texture2D, string title, string description)
            {
                using var mediaClass = new AndroidJavaClass(MediaStoreImagesMediaClass);
                using var cr = Activity.Call<AndroidJavaObject>("getContentResolver");
                var image = Texture2DToAndroidBitmap(texture2D);
                var imageUrl = mediaClass.CallStatic<string>("insertImage", cr, image, title, description);
                return imageUrl;
            }
    
            private static AndroidJavaObject Texture2DToAndroidBitmap(Texture2D texture2D)
            {
                var encoded = texture2D.EncodeToPNG();
                using var bf = new AndroidJavaClass("android.graphics.BitmapFactory");
                return bf.CallStatic<AndroidJavaObject>("decodeByteArray", encoded, 0, encoded.Length);
            }
        }

     

    Now where you take the screenshot you save it like this

     

                var appName = Application.identifier;
                var fileName = $"{appName}-{DateTime.Now:yyMMdd-hhmmss}";
    #if UNITY_EDITOR
                MiscExtensions.SaveScreenShotInternally(tex, fileName);
    #elif UNITY_ANDROID
                AndroidExtensions.SaveImageToGallery(tex, fileName, "Some description");
    #endif

     

     

    I changed the name of my screenshot to include the Application Identifier so in the Gallery it will show the app name. I wrote a method in my Misc extensions to save the image to the "persistentDataPath" while in the editor but that isn't super important to share.

     

    With this new version it will save to the gallery and will no longer need extra permissions to do so.

     

    ORIGINAL ACCEPTED POST:

     

    I figured this out and wanted to post the answer here as this is the first result on google when I was trying to figure this out.

    So first off I think the main solution is updating your android manifest with a few permissions.

     

     

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

     

     

    Also on your manifest there will be the application tag you need to include the requestLegacyExternalStorage like this.

     

     

    <application android:label="@string/app_name" android:icon="@mipmap/app_icon" android:allowBackup="false" android:requestLegacyExternalStorage="true">

     

     


    Once I had those updates on my manifest I was able to save to the screenshot folder like this.

     

     

    #if UNITY_EDITOR
                filePath = Path.Combine(Application.persistentDataPath, fileName);
    #elif UNITY_ANDROID
                filePath = Path.Combine("/sdcard/Oculus/Screenshots/", fileName);
    #endif
                File.WriteAllBytes(filePath, tex.EncodeToJPG());

     

     


    Though I was able to save into the correct folder, I can't seem to see the file in the gallery on the device. When I plug the device into my PC I can see the pictures in the screenshot folder and if I take the files out and put them on my PC and put them back into the same folder on device then I can see them in the gallery on the device. Not sure if it is due to my files not matching the naming convention of normal screenshots or if there is some permission I haven't figured out but I will keep poking at this.