0

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

Android Manifest xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.andrei.sendphotos">

<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>

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • can you show your android.manifest.xml – Donald Wu Nov 06 '16 at 11:45
  • I will update now the post. Take a look please at the last paragraph –  Nov 06 '16 at 11:56
  • http://stackoverflow.com/questions/26579869/how-can-i-let-users-access-the-internal-storage-directory-of-my-app – Donald Wu Nov 06 '16 at 11:58
  • What is the target SDK version you are using? – Kamran Ahmed Nov 06 '16 at 11:59
  • I am using the 23 target SDK –  Nov 06 '16 at 12:01
  • `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`. You should check your Bitmap pointer for `null` before use. – greenapps Nov 06 '16 at 13:17
  • The biggest problem with your code is that you use an outdated function like `getRealPathFromURI()`. Get rid of it and use the uri directly to open an inputstream using the content resolver. – greenapps Nov 06 '16 at 13:20

1 Answers1

1

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.


One of the major changes in Android 6.X was the enforced run-time permission model. Google had to keep backward compatibility for the applications already in the market (which don't check and ask for permissions on run-time).

So they made it work like - if the application targets SDK version 22, all the permissions will be granted to the application on installation. But if an application targets SDK 23, it will not be granted permissions by default, rather the application should check for permissions before performing any task that needs dangerous permissions and ask the user for it if not already granted before continuing the same.

Kamran Ahmed
  • 7,661
  • 4
  • 30
  • 55
  • After I Downgraded the emulator (the testing device) to the SDK 22 the app works fine! But I could not understand why it does not work on the 23 sdk. Could you explain please in a few words? –  Nov 06 '16 at 12:22
  • Thank you very much! This solved my problem that I could not solve for 3 days –  Nov 06 '16 at 14:14