-1

I have two problems with my app. First problem is that I get an IOException:permission denied even tho I would think I have already all the permissions that I need.

The method dispatchTakePictureIntent when I run photoFile = createImageFile() triggers the permission error.

The othe problem that I have is that I want to separate all the camera-stuff and file creation-stuff to separate classes. But what is the best way to pass information/variable data between classes in a good way. Is this something I should use callbacks or observers for? I would really be glad if someone could provide a simple example of how to do this.

MainActivity:

public class MainActivity extends AppCompatActivity {

    EncodeToBase64 encode = new EncodeToBase64();
    String lastPhotoAsBase64;
    ImageView mImageView;
    ImageView mBackground;

    private static int RESULT = 1;
    static final int REQUEST_TAKE_PHOTO = 1;
    static final int PICK_IMAGE_REQUEST = 2;
    String mCurrentPhotoPath;

    TextView textView;
    ProgressBar progress;

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


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
                checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RESULT);
        }

        setContentView(R.layout.activity_main);
        mImageView = findViewById(R.id.imageView);
        mBackground = findViewById(R.id.backgroundImage);
        Button cameraButton = findViewById(R.id.cameraButton);
        Button galleryButton = findViewById(R.id.galleryButton);
        textView = findViewById(R.id.textView);
        progress = findViewById(R.id.progressBar);

        cameraButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dispatchTakePictureIntent();
            }
        });

        galleryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
                startActivityForResult(galleryIntent, PICK_IMAGE_REQUEST);
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_TAKE_PHOTO && resultCode == RESULT_OK) {
            try {
                setPic();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if (requestCode == PICK_IMAGE_REQUEST && data.getData() != null) {
            Uri selectedImage = data.getData();

            try {
                String[] filePathColumn = {MediaStore.Images.Media.DATA};
                Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
                cursor.moveToFirst();
                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                String picturePath = cursor.getString(columnIndex);
                mCurrentPhotoPath = picturePath;
                cursor.close();

                setPic();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    private File createImageFile() throws IOException {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir =  getExternalStoragePublicDirectory(DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );
        // Save a file: path for use with ACTION_VIEW intents
        mCurrentPhotoPath = image.getAbsolutePath();
        galleryAddPic();
        return image;
    }

    private static int exifToDegrees(int exifOrientation) {
        if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
            return 90;
        } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
            return 180;
        } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
            return 270;
        }
        return 0;
    }
    private void galleryAddPic() {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        File f = new File(mCurrentPhotoPath);
        Uri contentUri = Uri.fromFile(f);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
    }


    public void setPic() throws IOException {
        // Get the dimensions of the View
        int targetW = mImageView.getWidth();
        int targetH = mImageView.getHeight();

        // Get the dimensions of the bitmap
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;

        //BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        // Determine how much to scale down the image
        int scaleFactor = Math.min(photoW / targetW, photoH / targetH);

        // Decode the image file into a Bitmap sized to fill the View
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;
        bmOptions.inPurgeable = true;

        Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);

        ExifInterface exif = new ExifInterface(mCurrentPhotoPath);
        int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        int rotationInDegrees = exifToDegrees(rotation);
        //int deg = rotationInDegrees;
        Matrix matrix = new Matrix();
        if (rotation != 0f) {
            matrix.preRotate(rotationInDegrees);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        }
        lastPhotoAsBase64 = encode.encode(bitmap);
        if (lastPhotoAsBase64 != null) {
            new postData().execute(lastPhotoAsBase64);
        } else {
            Toast.makeText(MainActivity.this, "No base64 data found!", Toast.LENGTH_LONG).show();
        }
        mImageView.setImageBitmap(bitmap);
    }


    public void dispatchTakePictureIntent() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            // Create the File where the photo should go
            File photoFile = null;
            try {
                photoFile = createImageFile();
            } catch (IOException ex) {
                // Error occurred while creating the File
                ex.printStackTrace();
            }
            // Continue only if the File was successfully created
            if (photoFile != null) {
                Uri photoURI = FileProvider.getUriForFile(this,
                        "com.example.fileprovider",
                        photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
            }
        }
    }

    public class postData extends AsyncTask<String, Void, String> {


        @Override
        protected String doInBackground(String... strings) {
            HttpConnectionActivity hh = new HttpConnectionActivity();
            String temp = hh.HttpConnection(strings[0]);
            return temp;
        }

        @Override
        protected void onPreExecute() {
            textView.setVisibility(View.INVISIBLE);
            progress.setVisibility(View.VISIBLE);
        }

        @Override
        protected void onPostExecute(String s) {

            progress.setVisibility(View.INVISIBLE);
            JSONObject jsonRaw = null;
            String age = null;
            String gender = null;
            String result = null;
            if(!(s.contains("5002"))) {
                try {
                    jsonRaw = new JSONObject(s);
                    age = jsonRaw.getJSONArray("images").getJSONObject(0).getJSONArray("faces").getJSONObject(0).getJSONObject("attributes").getString("age");
                    gender = jsonRaw.getJSONArray("images").getJSONObject(0).getJSONArray("faces").getJSONObject(0).getJSONObject("attributes").getJSONObject("gender").getString("type");
                    result = "Du är en " + ((gender.equals("M")) ? "Man" : "Kvinna") + " som är " + age + " år gammal";
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
            else{
                result = "Inga ansikten hittades";
            }
            textView.setText(result);
            textView.setVisibility(View.VISIBLE);
        }
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cliff.camera2">
    <uses-feature android:name="android.hardware.camera"
        android:required="true" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="18" />
    <uses-permission android:name="android.permission.INTERNET"/>



    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        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>
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.android.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"></meta-data>
        </provider>
    </application>
</manifest>

file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="DCIM/SkitApp" />
</paths>
Zoe
  • 27,060
  • 21
  • 118
  • 148
Burton
  • 407
  • 1
  • 6
  • 19
  • To be honest, this is truly a mess... I suggest you not to just copy and paste the code from somewhere, rather try to think critically and write the codes after you fully digest them. Have a deep look into basic concepts of programming, especially the concept and design of Object Oriented Programming. You will really need it. And for your error, do not just upload all your code. Instead, upload your error message and the specific piece of code that actually triggers the exception. The exception will always leave you with the call stack trace to track where it went wrong. – viz Dec 15 '17 at 22:23

1 Answers1

1

The CAMERA permission is a dangerous permission, so is WRITE_EXTERNAL_STORAGE. Starting in API 23 you have to request these permissions at runtime. Meaning even though you list it in the manifest, for API >= 23 you have to request them

Zoe
  • 27,060
  • 21
  • 118
  • 148