1

I can't quite get cwac to work, and looking at the demo code hasn't helped. I'm simply trying to export a pdf through a share intent. Currently the output is a "Can't attach empty file" error. But the file does exist, and I can't tell if the problem is with the file name, location, or cwac provider usage.

Here is how I've set up the provider.

        <provider
        android:name="com.commonsware.cwac.provider.StreamProvider"
        android:authorities="com.anothergamedesigner.CatVimeoTest.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="com.commonsware.cwac.provider.STREAM_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
    </provider>

This is my xml resource the provider is using. I set path to "" because I don't have any subdirectories. I don't know if those are required, but ideally I don't want to have to switch up my code elsewhere for the file restructure necessary to put the files in subdirectories. Although, if that's the problem, I suppose I could, but I don't see why the root shouldn't work.

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <asset name="assets" path=""/>
</paths>

Here is my PDFActivity (extends AppCompatActivity):

Variables:

private String pdfName //set in onCreate; ex. "This is my.pdf"

private static final String AUTHORITY = "com.anothergamedesigner.CatVimeoTest";
private static final Uri PROVIDER = Uri.parse("content://"+AUTHORITY);
private static final String ASSET_PATHS ="assets/";

Methods definitions:

private Intent getOpenPDFShareIntent(String name){
    Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
    shareIntent.setType("application/pdf");

    shareIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {""});
    shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.default_share_subject));
    shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, getResources().getString(R.string.default_share_text));

    shareIntent.putExtra(Intent.EXTRA_STREAM, getURI());
    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    shareIntent.setType("text/plain");
    return shareIntent;
}

private Uri getURI(){
    String path = ASSET_PATHS + pdfName;
    return(PROVIDER
            .buildUpon()
            .appendPath(StreamProvider.getUriPrefix(AUTHORITY))
            .appendPath(path)
            .build());

}

In getURI(), an example return for System.out.println(path) is: "assets/my.pdf"

The code runs via a menu button that on selection:

Intent shareIntent = getOpenPDFShareIntent(pdfName);
StartActivity(Intent.createChooser(shareIntent, getResources().getString(R.string.contact_send_mail));

EDIT: Attempting to remove null URIPrefix:

    private Uri getURI(){
    //String path = ASSET_PATHS + pdfName;

    if(StreamProvider.getUriPrefix(AUTHORITY) != null){
        return(PROVIDER
                .buildUpon()
                .appendPath(StreamProvider.getUriPrefix(AUTHORITY))
                .appendPath(ASSET_PATHS)
                .appendPath(pdfName)
                .build());
    } else{
        return(PROVIDER
                .buildUpon()
                .appendPath(ASSET_PATHS)
                .appendPath(pdfName)
                .build());
    }
}

EDIT 2 - Testing with DocumentFile:

I used these new methods from another SO answer and altered it to return the file.

private File CopyReadAssets()
{
    AssetManager assetManager = getAssets();

    InputStream in = null;
    OutputStream out = null;
    File file = new File(getFilesDir(), "my.pdf");
    try
    {
        in = assetManager.open("my.pdf");
        out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);

        copyFile(in, out);
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
    } catch (Exception e)
    {
        Log.e("tag", e.getMessage());
    }

    return file;
}

private void copyFile(InputStream in, OutputStream out) throws IOException
{
    byte[] buffer = new byte[1024];
    int read;
    while ((read = in.read(buffer)) != -1)
    {
        out.write(buffer, 0, read);
    }
}

Then I tested using:

DocumentFile aFile = DocumentFile.fromFile(CopyReadAssets());
DocumentFile file = DocumentFile.fromSingleUri(this, getURI());
System.out.println(aFile.getName());
System.out.println(aFile.length());
System.out.println(file.getName());
System.out.println(file.length());

It returns "my.pdf" and "33528" for aFile and "my.pdf" and "FileNotFoundException" for file.

NappyXIII
  • 195
  • 2
  • 17
  • I would start by fixing your MIME type. You are not sharing plain text. You are sharing `application/pdf`, and you are calling `setType()` twice. Also, get rid of `EXTRA_TEXT` until you get things working. `ACTION_SEND` supports *either* `EXTRA_TEXT` *or* `EXTRA_STREAM`, and so you may get one or the other but not both, depending on the implementation of the `ACTION_SEND` activity. Beyond that, what does the entire `Uri` look like that you get from `getURI()`? – CommonsWare Jul 22 '16 at 15:44
  • I've commented out those lines, and yeah, noticed that setType thing and removed it. Same problem, but probably best to do as you suggest. URI is: content://com.anothergamedesigner.CatVimeoTest/null/assets%2FCEGA%20OnBoard%20Support%201.6.compressed.pdf – NappyXIII Jul 22 '16 at 15:47
  • Any idea how the null portion might be arising from? – NappyXIII Jul 22 '16 at 15:47

2 Answers2

0
content://com.anothergamedesigner.CatVimeoTest/null/assets%2FCEGA%20OnBoard%20Su‌​pport%201.6.compressed.pdf

There are two problems here that I can see.

First, StreamProvider.getUriPrefix(AUTHORITY) is returning null. I don't know why, as you do not appear to be subclassing StreamProvider. That being said, you should check for null and skip that appendPath() statement if it is null.

Second, rather than ASSET_PATHS + pdfName, use two appendPath() statements. This should prevent the / from being converted into %2F.

Note that I have not tried files with spaces in the name, or anything else that has to get escaped, as you have in your filename. It's possible that there are bugs related to this. If changing the two items above do not help, try renaming the PDF temporarily to something simple. If that then works, I have a bug that I'll need to fix.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I tried doing as you said, but the first thing I notice is that the URI returned is "content://com.anothergamedesigner.CatVimeoTest/assets%2F/CEGA%20OnBoard%20Support%201.6.compressed.pdf" So the / is still being converted. – NappyXIII Jul 22 '16 at 16:06
  • @NappyXIII: Sorry, you should also remove that slash from `ASSET_PATHS`. – CommonsWare Jul 22 '16 at 16:08
  • Yeah, realized that too, just fixed it haha. – NappyXIII Jul 22 '16 at 16:10
  • So I tried hardcoding my.pdf and renaming one of my pdfs as that. My new URI is: "content://com.anothergamedesigner.CatVimeoTest/assets/my.pdf" and I still get an empty file. So my next guess would be that I have to solve the URIPrefix problem, because it doesn't seem to be the spaces that cause the issue. – NappyXIII Jul 22 '16 at 16:14
  • I tried to put the my.pdf in a subdirector too, to see if there was a bug with the (paths="") portion of the paths xml, no dice. – NappyXIII Jul 22 '16 at 16:18
  • @NappyXIII: Part of the problem here is that you aren't in control over both ends of the communications. We're just guessing as to what "Can't attach empty file" means, and I do not even know what app you are trying. Throw together a test case that confirms that you can access your own `Uri` and that is has your content. Or, if you don't have instrumentation testing going, do that from within your activity somewhere. You can use `DocumentFile` to quickly confirm that the length and filename seem fine, as a starting point. – CommonsWare Jul 22 '16 at 16:40
  • Ok, so I noticed that I was passing the package name instead of the provider. I solved the issue where I was getUriPrefix was returning null and now I have: "content://com.anothergamedesigner.CatVimeoTest.provider/d72b34d7-b757-4a92-bbd8-c848f455000c/assets/my.pdf". I then tested with File file = new File(getURI().getPath()); and printed file.getName() and file.length(). The name returns correctly as "my.pdf", however, when printing the length to get the file size, it returns 0 and says "stat failed: ENOENT (No such file or directory) : /d72b34d7-b757-4a92-bbd8-c848f455000c/assets/my.pdf" – NappyXIII Jul 26 '16 at 16:37
  • "I then tested with File file = new File(getURI().getPath()); " -- no. `DocumentFile`. Not `File`. – CommonsWare Jul 27 '16 at 00:07
  • Retested with DocumentFile using DocumentFile file = DocumentFile.fromSingleUri(getUri()); Returned W/AssetStrategy: Exception getting asset length FileNotFoundException /my.pdf. Content path was tsill the same as my last comment. If I'm not getting the length, what should I do as my next step? – NappyXIII Jul 27 '16 at 14:44
  • I tried implementing a method from http://stackoverflow.com/questions/17085574/read-a-pdf-file-from-assets-folder and the results are above. So the file does exist, but through your library I can't find a way yet to make the uri provided by your library to pull the asset. – NappyXIII Jul 27 '16 at 15:04
  • If I had to guess, your problem is compression. Add `aaptOptions` per [the documentation](https://github.com/commonsguy/cwac-provider#gradle-settings) and see if that helps. – CommonsWare Jul 28 '16 at 00:13
  • Unfortunately, I've had that since the beginning. – NappyXIII Jul 28 '16 at 13:13
  • If you can publish a reproducible test case, [file an issue](https://github.com/commonsguy/cwac-provider/issues). At this point, I am out of ideas. – CommonsWare Jul 28 '16 at 13:22
  • I figured it out just now. I changed my ASSET_PATHS to "assets/my.pdf" (as opposed to the "assets" and String pdfName that is appended afterwards, trying just about anything to see if I could get a different result) and it attached it properly. I'm not sure why this worked, but it fixed the problem... – NappyXIII Jul 28 '16 at 13:51
  • One thing I do notice is that my URI is now: content://com.anothergamedesigner.MUV.provider/ded51629-4f93-45da-b454-e302de2e8da6/assets%2Fmy.pdf I'll post my final code above. – NappyXIII Jul 28 '16 at 13:59
  • I'd like to note that spaces did not cause any problems when using the final pdfs. Not sure about escape characters, but tere were spaces and periods in several of my PDFs so you do not have a bug there. – NappyXIII Jul 28 '16 at 14:13
0

FINAL CODE

The problem is seems was with ASSET_PATHS. Appending the pdfName to "assets" proved to be problematic for some reason. Because of this I chose to change ASSET_PATHS from a final and then set it in the onCreate method. This would be one way to do it, or you could hard code in the different pdfs such as in the demo project.

public class PDFViewActivity extends AppCompatActivity {

private String pdfName;
...

private static final String AUTHORITY = "com.your.provider";
private static final Uri PROVIDER = Uri.parse("content://"+AUTHORITY);
private static String ASSET_PATHS;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Bundle extras = getIntent().getExtras();
    pdfName = extras.getString("pdfName");
    ...

    ASSET_PATHS = "assets/" + pdfName;

    // Place an PDFViewFragment as our content pane
    PDFViewFragment f = new PDFViewFragment();
    getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_pdf, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
        case R.id.menu_button_share:
            Intent shareIntent = getOpenPDFShareIntent();
            startActivity(Intent.createChooser(shareIntent, "Send Email"));
            return true;
        ...
        default:
            return super.onOptionsItemSelected(item);
    }
}

private Intent getOpenPDFShareIntent(){
    Intent shareIntent = new Intent(Intent.ACTION_SEND);
    shareIntent.setType("application/pdf");

    shareIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {""});
    shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.default_share_subject));
    shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, getResources().getString(R.string.default_share_text));
    shareIntent.putExtra(Intent.EXTRA_STREAM, getURI());
    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    shareIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

    return shareIntent;
}

private Uri getURI(){
    return(PROVIDER
            .buildUpon()
            .appendPath(StreamProvider.getUriPrefix(AUTHORITY))
            .appendPath(ASSET_PATHS)
            .build());
}

}

NappyXIII
  • 195
  • 2
  • 17