xz ayt xz ayt - 1 month ago 11
Android Question

Android Unable to decode stream: java.io.FileNotFoundException for bitmapFactory.decodeFile()

I have an android app where I take a photo from camera and then I would like to convert it to the base64 format but I have an error after accepting the taken photo. It seems like I don't have access to the external storage and I think this leads to a null bitmap. THE PERMISSIONS IN THE ANDROID_MANIFEST HAVE BEEN DECLARED. How can I resolve the permission problem and what may lead to a null bitmap?

here is my code:

public class MainActivity extends AppCompatActivity {

private Button takePhotoButton;
private String encoded_string, image_name;
private Bitmap bitmap;
private File file;
private Uri file_uri;


private String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(this, contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

takePhotoButton = (Button) findViewById(R.id.take_photo);
takePhotoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
getFileUri();
i.putExtra(MediaStore.EXTRA_OUTPUT, file_uri);
startActivityForResult(i, 10);
}
});
}


private void getFileUri() {
image_name= "test123.jpg";
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + image_name);
file_uri = Uri.fromFile(file);
}



@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == 10 && resultCode == RESULT_OK){
new Encode_image().execute();
}
}


private class Encode_image extends AsyncTask<Void, Void, Void>{

@Override
protected Void doInBackground(Void... params) {

BitmapFactory.Options options = new BitmapFactory.Options();

int scale = 8;
options.inSampleSize = scale;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(file_uri.getPath(), options);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream);




//convert stream to byte array
byte[] array = stream.toByteArray();
encoded_string = Base64.encodeToString(array, 0);
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
makeRequest();
}
}

private void makeRequest() {
RequestQueue requestQueue = Volley.newRequestQueue(this);
StringRequest request = new StringRequest(Request.Method.POST, "http://192.168.1.102/AndroidFileUpload/connection.php",

new Response.Listener<String>() {
@Override
public void onResponse(String response) {

}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {

}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> map = new HashMap<>();
map.put("encoded_string", encoded_string);
map.put("image_name", image_name);

return map;
}
};
requestQueue.add(request);
}


}


I get the error in the line

bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream)


because the bitmap is null.

The crash after running the app returned this errors/messages:

E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/Pictures/test123.jpg: open failed: EACCES (Permission denied)
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.andrei.sendphotos, PID: 17972
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
at com.example.andrei.sendphotos.MainActivity$Encode_image.doInBackground(MainActivity.java:115)
at com.example.andrei.sendphotos.MainActivity$Encode_image.doInBackground(MainActivity.java:92)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
at java.lang.Thread.run(Thread.java:818) 
E/Surface: getSlotFromBufferLocked: unknown buffer: 0xa23ae0e0


Manifest:

<?xml version="1.0" encoding="utf-8"?>




<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>



Answer

You need to implement run-time permissions for Android 6.X. Refer the official documentation here: Requesting Runtime Permissions

There are public helper classes available like one of my own here: PermissionHelper.java

Or you could simply downgrade your target SDK version to 22 and all the dependencies too, which I wouldn't recommend.