1

I have spent days reading the docs and following various tutorials for this but I am getting errors whatever I do. I am trying to save an image in Internal Storage and then convert it to a content Uri so that I can use the system crop and resize function. If anyone could spot where my code is wrong I would be very grateful:

Main Activity:

new Thread(() -> {
try {
    String temp = "temp";

    //Convert bitmap to byte array
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
    byte[] bitmapData = bos.toByteArray();

    //Write the bytes in file
    FileOutputStream fos = openFileOutput(temp, MODE_PRIVATE);
    fos.write(bitmapData);
    fos.flush();
    fos.close();

    //Convert file to contentUri
    File file = new File(getFilesDir(), temp);

    Intent intent = new Intent();
    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    Uri imageUri = FileProvider.getUriForFile(MainActivity.this, "@string/file_provider_authority", file);
    intent.setDataAndType(imageUri, "image/jpg");

    intent = WallpaperManager.getInstance(getApplicationContext()).getCropAndSetWallpaperIntent(imageUri);
    startActivityForResult(intent, ACTIVITY_CROP);

} catch (Exception e) {
    e.printStackTrace();
}
}).start();

Manifest:

<provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="@string/file_provider_authority"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_provider_paths" />
    </provider>
</application>

file_provider_paths.xml:

<paths>
<files-path
    path="/" name="temp" />

strings.xml:

<resources>
<string name="file_provider_authority"
    translatable="false">com.me.wallpaper_app.provider
</string>

Error:

    W/System.err(12162): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference
    W/System.err(12162):    at android.support.v4.content.FileProvider.parsePathStrategy(FileProvider.java:604)
    W/System.err(12162):    at android.support.v4.content.FileProvider.getPathStrategy(FileProvider.java:578)
    W/System.err(12162):    at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:416)
    W/System.err(12162):    at com.me.wallpaper_app.MainActivity$1$1.lambda$onResourceReady$0$MainActivity$1$1(MainActivity.java:82)
    W/System.err(12162):    at com.me.wallpaper_app.-$$Lambda$MainActivity$1$1$Xm-7yym42zTgTZOFP5GGtbF6p2U.run(Unknown Source:4)
    W/System.err(12162):    at java.lang.Thread.run(Thread.java:919)
Code Poet
  • 6,222
  • 2
  • 29
  • 50

2 Answers2

2

"@string/file_provider_authority" is not how you reference string resources in Java. Use getString(R.string.file_provider_authority).

UPDATE: Based on the comments, the second major problem is that the consumer of this content isn't using the MIME type from the Intent, but instead is calling getType() on a ContentResolver to get the type from the ContentProvider. In this case, that is your FileProvider, and FileProvider only knows how to work with file extensions and converting those to MIME types. So, using temp.jpeg gave FileProvider the information necessary to return the proper MIME type.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Oh, thanks for this! And now I am getting this error: "Cannot use passed URI to set wallpaper; check that the type returned by ContentProvider matches image/*". But I did set the data and type to image. Hmm... – Code Poet May 25 '19 at 15:51
  • @user9480972: Try `"image/jpeg"` instead of `"image/jpg"` for the MIME type. – CommonsWare May 25 '19 at 15:58
  • @user9480972: Change `setFlags()` to `addFlags()` in both places. Right now, your second `setFlags()` call overwrites the result from the first one. – CommonsWare May 25 '19 at 16:30
  • Ok, done. I am obviously doing something else wrong because this is what I am now getting: "I/System.out(20634): Image Data and Type = Intent { dat=content://com.me.wallpaper_app.provider/files/temp typ=image/* flg=0x3 } I/System.out(20634): Image Uri = content://com.me.wallpaper_app.provider/files/temp W/System.err(20634): java.lang.IllegalArgumentException: Cannot use passed URI to set wallpaper; check that the type returned by ContentProvider matches image/* Should I call "temp" differently? Like "image" for instance? – Code Poet May 25 '19 at 16:41
  • @user9480972: Use `image/jpeg`, not `image/*`, in the `Intent`. I also suggest switching from `openFileOutput()` to creating a `FileOutputStream` directly using the same `File` object that you use with `FileProvider.getUriForFile()`. Then, use `compress()` directly with that `FileOutputStream` (getting rid of the `ByteArrayOutputStream` intermediary). Finally, use `temp.jpg` or `temp.jpeg` for the filename, in case the wallpaper stuff is ignoring the MIME type in the `Intent` and asking `FileProvider` for the MIME type`. – CommonsWare May 25 '19 at 16:49
  • Using "temp.jpeg" for the filename did the trick. Will adapt my code to what you suggest too. Really grateful. – Code Poet May 25 '19 at 16:57
0

Try This

      Uri imageUri = FileProvider.getUriForFile(MainActivity.this, R.string.file_provider_authority, file);

Also Change

    <paths>
    <files-path
    path="/" name="temp" />

To

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android"> 
    <external-path name="external_files" path="."/>
    </paths>
Siddarth Jain
  • 304
  • 1
  • 6