2

I have an app similar to an explorer and allow the user to share folders, multiple folders and multiple files. The share intent will hold a list of all shared files in the end.

If the user shares a folder with 1000 files, this is just to much. But how can I determine if it's possible to share the amount of files the user selected?

I want to check if it's possible to share the amount of files the user selected and if not, I want to tell him that he selected to much files and reached an android limit. In the best case I would like to tell him that his share intent is let's say 2.5MB and that the limit is 1MB, so he can estimate by himself how many files he should select...

Question

  • Is it possible to determine if a share intent is < 1MB and therefore is possible to be shared?
  • Is it possible to determine the size of a share intent?

Edit

To eliminat confusion:

I don't share files directly in the intent, but only the URI or relative path to the files. So the length of the URI or the length of the relative path is important for the size of the intent, but not if it points to big or small files.

The 1MB limit is valid for the intent (parceled intend I think) and if the intent holds to much data, it will fail SILENTLY and that's the problem

I'm looking for a reusable solution, that works with ANY intent! I am sometimes adding share targets and sometimes not.

prom85
  • 16,896
  • 17
  • 122
  • 242

5 Answers5

1

For Intent:

You can write that intent object to a Parcel and use dataSize() method to get serialized data size contained in that intent. Make sure to recycle() the parcel afterwards.

    final Intent testIntent = getIntent();
    final Parcel testParcel = Parcel.obtain();
    try {
        testParcel.writeParcelable(testIntent,0);
        Log.i("TEST", String.format("Intent size: %s", testParcel.dataSize()));
    }finally {
        testParcel.recycle();    
    }

For files:

If you can retrieve list of file names from intent, then you can query each file size and sum it up:

sizeBytes += new File(filePath).length();

For a directory though you'll need to walk and add up the size of all files under it. You can use DirectoryWalker class for this.

S.D.
  • 29,290
  • 3
  • 79
  • 130
  • I recently added a comment to my question... I need another size. I need the parceled size of the resulting intent... It's independent of the file sizes, it only depends on the size of the URIs or paths and of course on the amount of shared files... – prom85 May 23 '16 at 07:53
  • @prom85 see first part of answer. – S.D. May 23 '16 at 07:56
0

Why don't call a shell command to get a size of files?

It won't determine intent size exactly but gives you a nice prediction.

try {
    Process process = Runtime.getRuntime().exec("ls -l");
    BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
} catch (InterruptedException e) {
    e.printStackTrace();
}

Ensure you don't use awk and other which can be unavailable on some devices. For directories sizes you will need to use something different than ls.

klimat
  • 24,711
  • 7
  • 63
  • 70
  • I'm not sharing files, I'm sharing links to files... It does not matter if I share 50 videos or 50 text files, but the length of the shared address is important... – prom85 May 23 '16 at 07:42
  • Can't you iterate through all links and calculate their size? – klimat May 23 '16 at 07:44
  • I updated my question... I can iterate over them, but we are talking about different sizes... Hopefully my edit explains it – prom85 May 23 '16 at 07:45
  • Why you can't iterate through the links? – klimat May 23 '16 at 07:46
  • I don't know how much size a link/URI in the intent will take up... The intent will be parceled and then it's not allowed to be > 1MB... I need the size of the parceled intend. As android is limiting this – prom85 May 23 '16 at 07:51
0

It might make more sense to put a sensible worse case number on it. "You have shared too many files (1005/1000 files)" would be a useful message. Telling a user they've shared too many bytes will be confusing when you're referring to the length of file names, not size of the files.

The worst case file name is 127 characters or 255 bytes.

1MB/256 = 4096

So, I would think 4000 would be risky, but 2000-3000 should be fine, depending on the size of the rest of your payload.

If you think that's not enough for your users, then you need a different solution, not a warning.

Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203
  • As above, this may be possible if the intent is not holding any other data (like share target or anything else). Then I can calculate the base size with no shared file and add the sizes for all files... – prom85 May 23 '16 at 08:41
  • @prom85 as I say "depending on the size of the rest of your payload." (And I don't know what "above" refers to if not the question, as answers jump around.) – weston May 23 '16 at 08:46
  • I just copied my answer (that's why I said as above). It's refering to the other answer about calculating the size of the paths... And sharing files is not sharing paths, it can be URIs (probably shorter than paths) as well. But I think the one answer that really calculates the size of the intent via parceling it is the solution I'm looking for... – prom85 May 23 '16 at 08:52
0

what you could do is that you keep reference to the file names length that are being selected to avoid looping through them later.

1 character = 1 byte. so, about 1000 characters equal 1 kilobyte.

so base on this you could limit the user selection and be able to actually tell them while they are selecting the files, that they reached the maximum number of files to select(a general message). example code:

private int maxLength = 0;

    onSelectFile(File file){
        maxLength += file.getName().length()
        if(maxLength < 1mb ){//display massage and dont add the new selected file}
    }
Kosh
  • 6,140
  • 3
  • 36
  • 67
  • This may be possible if the intent is not holding any other data (like share target or anything else). Then I can calculate the base size with no shared file and add the sizes for all files... – prom85 May 23 '16 at 08:41
0

I believe there's no direct way of checking it, but you can do a manual work on it to get the size of your intent.

Considering that Intent implements Parcelable you should be able to get a Parcel, write to it, and check it's size before sending/launching the intent. Something like that:

Intent intent = ....
... do your intent and fill with the URI data.

Parcel parcel = Parcel.obtain();
intent.writeToParcel(parcel, 0);
int size = parcel.dataSize(); // HERE IS THE NUMBER YOU WANT TO CHECK
parcel.recycle(); // don't forget to return the parcel to the system
parcel = null;

I'm not sure if that size is in bytes, but it should be. If you want the official docs are here https://developer.android.com/reference/android/os/Parcel.html

On a user experience note, you might want to keep checking the size as the user selects stuff, so that once the limit is reached, you can block the user from selecting any extra itens and thou don't waste user time.

Budius
  • 39,391
  • 16
  • 102
  • 144
  • as someone else suggested as well... I think, this is the most reusable solution in the end – prom85 May 23 '16 at 08:57