4

I previously used external storage to store specific data that I would like to share between my applications (without having any contentprovider "host")

File folder = new File(Environment.getExternalStorageDirectory(), "FOLDER_NAME");
File file = new File(folder, "FILE_NAME.dat");
FileOutputStream outputStream = new FileOutputStream(file);

That is why I am trying to use BlobStoreManager, as suggested in google's recommendation for targeting 30 (https://developer.android.com/training/data-storage/shared/datasets)

The read & write are based on a BlobHandle with 4 parameters, one being MessageDigest based on a "content". BlobHandle must use the same 4 parameters, or read will fail (SecurityException).

I managed to write data, and to read it, but it makes no sense: It seems that in order to write, I need to use the data I want to write to generate the BlobHandle.

Then, to read, as BlobHandle must use the same 4 parameters, I also need the data I wrote to be able to read. Totally illogic, as I wanted to read this data, I don't have it!

I must miss something or just do not understand how it work. If someone can help :)

Here are my sample:

If I set the following:

  • createBlobHandle: content = "mydata"
  • write: data = "mydata"
  • Then write will success, and read will success too. But it I can not know the value before reading it in a normal usecase :(

If I set the following (which would be logic, at least to me):

  • createBlobHandle: content = "somekey"
  • write: data = "mydata"
  • Then write will fail :(
@RequiresApi(api = Build.VERSION_CODES.R)
private BlobHandle createBlobHandle() {
    //Transfer object
    String content = "SomeContentToWrite";
    String label = "label123";
    String tag = "test";

    //Sha256 summary of the transmission object
    try {
        byte[] contentByte = content.getBytes("utf-8");

        MessageDigest md = MessageDigest.getInstance("sha256");
        byte[] contentHash = md.digest(contentByte);

        return BlobHandle.createWithSha256(contentHash, label,0, tag);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return null;
}

private void write() {
    String data = "SomeContentToWrite";
    @SuppressLint("WrongConstant") final BlobStoreManager blobStoreManager = ((BlobStoreManager) applicationContext.getSystemService(Context.BLOB_STORE_SERVICE));

    //Generate the session of this operation
    try {
        BlobHandle blobHandle = createBlobHandle();
        if (blobHandle == null)
            return;
        long sessionId = blobStoreManager.createSession(blobHandle);
        try (BlobStoreManager.Session session = blobStoreManager.openSession(sessionId)) {
            try (OutputStream pfd = new ParcelFileDescriptor.AutoCloseOutputStream(session.openWrite(0, data.getBytes().length))) {
                //The abstract of the written object must be consistent with the above, otherwise it will report SecurityException
                Log.d(TAG, "writeFile: >>>>>>>>>>text = " + data);
                pfd.write(data.getBytes());
                pfd.flush();

                //Allow public access
                session.allowPublicAccess();
                session.commit(applicationContext.getMainExecutor(), new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) {
                        //0 success 1 failure
                        Log.d(TAG, "accept: >>>>>>>>" + integer);
                    }
                });
            }
        }
    } catch (IOException e) {
            e.printStackTrace();
    }
}

private String read() {
    String data = "";
    @SuppressLint("WrongConstant") final BlobStoreManager blobStoreManager = ((BlobStoreManager) applicationContext.getSystemService(Context.BLOB_STORE_SERVICE));

    BlobHandle blobHandle = createBlobHandle();
    if (blobHandle != null) {
        try (InputStream pfd = new ParcelFileDescriptor.AutoCloseInputStream(blobStoreManager.openBlob(createBlobHandle()))) {
            //Read data
            byte[] buffer = new byte[pfd.available()];
            pfd.read(buffer);
            String text = new String(buffer, Charset.forName("UTF-8"));
            Log.d(TAG, "readFile: >>>>>>>>>>>>>>>>>>>>" + text);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }
    return data;
}
Thomas Thomas
  • 824
  • 1
  • 9
  • 21
  • `Then write will fail :(` Tried your code. But then the read() will fail here. Documentation is terrible. Examples on internet tooo vague too. – blackapps Feb 23 '21 at 12:20
  • `previously used external storage to store specific data that I would like to share between my applications` This is still possible on Android 11 devices. – blackapps Feb 23 '21 at 12:58
  • In my example, read & write work. But this is because I use "SomeContentToWrite" in both "BlobHandle" and write. But the problem is here; I don't know the data I wrote before reading it, so how could I create the BlobHandle used to read... :( – Thomas Thomas Feb 23 '21 at 16:40
  • Yes, it is still possible, but only if requesting MANAGE_EXTERNAL_STORAGE. This permission will not be granted by Google to all applications, and will require to fill a form, like everry "restricted permissions" (READ_CALL_LOG, READ_SMS, ACCESS_FINE_LOCATION, etc...) See https://support.google.com/googleplay/android-developer/answer/9888170 – Thomas Thomas Feb 23 '21 at 16:43
  • `But the problem is here; I don't know the data I wrote before reading it, ` Yes i knew already. And i tried your code and can confirm the same problem. I think it is not in for the task you and i would want to use it. – blackapps Feb 23 '21 at 16:47
  • `, but only if requesting MANAGE_EXTERNAL_STORAGE.` No. Not needed. – blackapps Feb 23 '21 at 16:48
  • I use WRITE_EXTERNAL_STORAGE in my apps, to save to a specific folder (as added to my post). Maybe am I wrong, but apparently WRITE_EXTERNAL_STORAGE has no effects in Android 11 without MANAGE_EXTERNAL_STORAGE. Explained here:https://developer.android.com/training/data-storage#permissions – Thomas Thomas Feb 23 '21 at 17:01
  • You are still wrong. – blackapps Feb 23 '21 at 17:02
  • Do you mean that I can still write with the sample code I added in my post, with just WRITE_EXTERNAL_STORAGE? But then what does mean the Google's documentation my latest link? (maybe it is just my bad english and I do not understand it :) – Thomas Thomas Feb 23 '21 at 17:04
  • "In particular, if your app targets Android 11 (API level 30) or higher, the WRITE_EXTERNAL_STORAGE permission doesn't have any effect on your app's access to storage. Android 11 introduces the MANAGE_EXTERNAL_STORAGE permission, which provides write access to files outside the app-specific directory" – Thomas Thomas Feb 23 '21 at 17:06
  • Not with that sample code. I will not answer here as this post is about using BlobStoreManager. Please write another post where you explain how you used to use external storage between your apps and wanna do something like that for Android 11. – blackapps Feb 23 '21 at 17:08
  • Apps can exchange data in files but cannot change or delete each others files. Only their own. Dont know what you need. – blackapps Feb 23 '21 at 17:18
  • I wrote a new question as you requested, with an exemple of what I was doing. https://stackoverflow.com/questions/66338001/use-external-storage-to-write-file-used-by-multiple-applications-on-android-11 – Thomas Thomas Feb 23 '21 at 17:23

1 Answers1

2

According to the official training documentation linked in the question, the missing piece of information, at the time of the question having been asked, is that the four pieces of data contained in the BlobHandler need to be uploaded to a server owned by the client application then subsequently downloaded by which ever other application wants to access the blob via the BlobStorageManager.

So it would seem that on-device blob discovery is not supported. There could also be a solution possible using a Content Provider which could offer up the four required pieces of data, thus circumventing the need for the server infrastructure.

enter image description here

Hrafn
  • 2,867
  • 3
  • 25
  • 44