0

I use broadcastreceiver of media folder android.hardware.action.NEW_PICTURE service to rename and move image using this code and it was running:

CameraReciver package perim.ebrahimi.ir.perim;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;

public class CameraReciver extends BroadcastReceiver {

    private States states;
    private SessionManager session;
    private WriteService main;

    @Override
    public void onReceive(Context context, Intent intent) {
        getStates(context);
        if(states.getAPP()){

            Cursor cursor = context.getContentResolver().query(intent.getData(), null, null, null, null);
            cursor.moveToFirst();
            if(cursor!=null){
                String image_path = cursor.getString(cursor.getColumnIndex("_data"));
                main = new WriteService();
                main.writeFolder(image_path, states, context);
            }
            cursor.close();
        } else abortBroadcast();
    }

    // OK
    private void getStates(Context context){
        session = new SessionManager(context.getApplicationContext());
        states = new States();
        states = session.getSession();
    }

}

and here is WriteService:

package perim.ebrahimi.ir.perim;

import android.app.Activity;
import android.app.Application;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class WriteService extends Activity {

    private States states;
    private Context context;
    private static CalendarJalalian cal;
    private static int day   ;
    private static int month ;
    private static int year  ;
    private static int saat  ;
    private static int minut ;
    private static int secnd ;
    private int orientation = -1;
    private static final int REQUEST_EXTERNAL_STORAGE = 100;
    private static final int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS=200;
    private boolean mExternalStorageAvailable = false;
    private boolean mExternalStorageWriteable = false;

//    @Override
//    protected void onCreate(Bundle savedInstanceState) {
//        super.onCreate(savedInstanceState);
//        //setContentView(R.layout.activity_main);
//
//        // A simple check of whether runtime permissions need to be managed
//        if (Build.VERSION.SDK_INT >= 23) {
//            checkMultiplePermissions();
//        }
//    }

    public void writeFolder(String image_path, States _states, Context _context){
        states = _states;
        context=  _context;
        cal = new CalendarJalalian();
        long fileSize = new File(image_path).length();
        Cursor mediaCursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[] {MediaStore.Images.ImageColumns.ORIENTATION,
                        MediaStore.MediaColumns.SIZE },
                MediaStore.MediaColumns.DATE_ADDED + ">=?",
                new String[]{String.valueOf(cal.getTimeInMillis()/1000 - 1)},
                MediaStore.MediaColumns.DATE_ADDED + " desc");
        if (mediaCursor != null && mediaCursor.getCount() !=0 ) {
            while(mediaCursor.moveToNext()){
                long size = mediaCursor.getLong(1);
                if(size == fileSize){
                    orientation = mediaCursor.getInt(0);
                    break;
                }
            }
        }
        orientation = (orientation<0)?0:orientation;
        image_path = changeName(image_path);
        if(image_path.length()==0) return;
        String image_jadid = copyFile(image_path);
        if(states.getMain() && image_jadid.length()>0){
            removeMain(image_path);
            removeMedia(context, new File(image_path));
        }
        if(states.getPayam()) Toast.makeText(this, getText(R.string.imageSaved)+": "+states.getKhas(), 500).show();

    }

    private void checkExternalStorage(){
        String[] aaa = new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE};
        ActivityCompat.requestPermissions(this, aaa , REQUEST_EXTERNAL_STORAGE);
        if(ContextCompat.checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE);
        } else {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)) {
                mExternalStorageAvailable = mExternalStorageWriteable = true;
            } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
                mExternalStorageAvailable = true;
                mExternalStorageWriteable = false;
            } else {
                mExternalStorageAvailable = mExternalStorageWriteable = false;
            }
        }
    }

    private static void removeMedia(Context context, File f) {
        ContentResolver resolver = context.getContentResolver();
        resolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media.DATA + "=?", new String[] { f.getAbsolutePath() });
    }

    // OK
    private String changeName(String image_path){
        String result = "";
        day   = cal.getDay();
        month = cal.getMonth();
        year  = cal.getYear();
        saat  = Integer.parseInt(cal.getHHour());
        minut = Integer.parseInt(cal.getMinute());
        secnd = Integer.parseInt(cal.getSecond());

        String persianDateName = String.format("%1$s_%2$s_%3$s__%4$s_%5$s_%6$s.jpg",
                year,
                ((month<10)?"0"+month:month),
                ((day<10)?"0"+day:day),
                ((saat<10)?"0"+saat:saat),
                ((minut<10)?"0"+minut:minut),
                ((secnd<10)?"0"+secnd:secnd));

        File from = new File(image_path);
        if(from.exists()){
            if(states.getOnimage()){
                addTextToImage(image_path, persianDateName);
            }
            File to = new File(from.getParentFile(),persianDateName);
            try
            {
                boolean b = from.renameTo(to);
                if (!b) {
                    copy(from, to);
                    from.delete();
                }
                removeMedia(context, from);
                sendToMedia(to, persianDateName);
                result = to.getAbsolutePath();
            }
            catch(Exception ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

    private void addTextToImage(String from, String persianDateName) {
        Log.i("info","Draw "+persianDateName+" on image");
        try
        {
            Log.i("info","1");
            FileOutputStream fos = new FileOutputStream(from);
            if(fos==null) Log.i("info","fos = null");

            Log.i("info","2 = "+from);
            Bitmap bitmap = BitmapFactory.decodeFile(from);
            if(bitmap==null) Log.i("info","bitmap = null");

//          Log.i("info","3");
            android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
            if(bitmapConfig==null) Log.i("info","bitmapConfig = null");

//          Log.i("info","4");
//          if (bitmapConfig == null) {
//              bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
//          }

            Log.i("info","5");
            bitmap = bitmap.copy(bitmapConfig, true);

            Log.i("info","6");
            Canvas canvas = new Canvas(bitmap);

            Log.i("info","7");
            Resources resources = this.getResources();
            float scale = resources.getDisplayMetrics().density;

            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            paint.setColor(Color.rgb(61, 61, 61));
            paint.setTextSize((int) (14 * scale));
            paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
            Rect qab = new Rect();
            paint.getTextBounds(persianDateName, 0, persianDateName.length(), qab);
            int x = (bitmap.getWidth() - qab.width()) / 2;
            int y = (bitmap.getHeight() + qab.height()) / 2;
            canvas.drawText(persianDateName, x, y, paint);

            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        Log.i("info","Text added on image");
    }

    private void copy(final File f1, final File f2) throws IOException {
        if(f2.exists()) f2.delete();
        //checkExternalStorage();
        checkMultiplePermissions();
        if(mExternalStorageAvailable && mExternalStorageWriteable) {
            f2.createNewFile();
            final RandomAccessFile file1 = new RandomAccessFile(f1, "r");
            final RandomAccessFile file2 = new RandomAccessFile(f2, "rw");
            file2.getChannel().write(file1.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, f1.length()));
            file1.close();
            file2.close();
        }
    }

    private boolean canRename(final File f1, final File f2) {
        final String p1 = f1.getAbsolutePath().replaceAll("^(/mnt/|/)", "");
        final String p2 = f2.getAbsolutePath().replaceAll("^(/mnt/|/)", "");
        return p1.replaceAll("\\/\\w+", "").equals(p2.replaceAll("\\/\\w+", ""));
    }

    // OK
    private void removeMain(String image_path){
        File f = new File(image_path);
        if(f.exists()) f.delete();
    }


    // OK
    private File createFileName(){
        day   = cal.getDay();
        month = cal.getMonth();
        year  = cal.getYear();
        saat  = Integer.parseInt(cal.getHHour());
        minut = Integer.parseInt(cal.getMinute());
        secnd = Integer.parseInt(cal.getSecond());

        String persianDateName = String.format("%1$s_%2$s_%3$s__%4$s_%5$s_%6$s.jpg",
                year,
                ((month<10)?"0"+month:month),
                ((day<10)?"0"+day:day),
                ((saat<10)?"0"+saat:saat),
                ((minut<10)?"0"+minut:minut),
                ((secnd<10)?"0"+secnd:secnd));

        String masirFolder = "";

        if(states.getSal())   masirFolder += year;
        if(states.getMah())   masirFolder += File.separator+ year+"_"+((month<10)?"0"+month:month);
        if(states.getRuz())   masirFolder += File.separator+ year+"_"+((month<10)?"0"+month:month)+"_"+((day<10)?"0"+day:day);

        if(states.getSaat())  masirFolder += File.separator+ year+"_"+((month<10)?"0"+month:month)+"_"+((day<10)?"0"+day:day)+"_"+((saat<10)?"0"+saat:saat);
        if(states.getMinut()) masirFolder += File.separator+ year+"_"+((month<10)?"0"+month:month)+"_"+((day<10)?"0"+day:day)+"_"+((saat<10)?"0"+saat:saat)+"_"+((minut<10)?"0"+minut:minut);

        if(states.getKhas().length()>0) masirFolder += File.separator+states.getKhas();

        File directTime = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), masirFolder);

        if (!directTime.mkdir()) makeDir(directTime);

        directTime = new File(directTime, persianDateName);

        return directTime;

    }

    // OK
    private void makeDir(File direct){
        direct.mkdirs();
    }

    // OK
    private String copyFile(String image_path){
        String masir = "";
        File sourceFile = new File(image_path);
        if (!sourceFile.exists()) {return masir;}
        File destinationFile = createFileName();
        FileChannel source = null;
        FileChannel destination = null;

        try {
            source = new FileInputStream(sourceFile).getChannel();
            destination = new FileOutputStream(destinationFile).getChannel();
            if (destination != null && source != null) {
                destination.transferFrom(source, 0, source.size());
            }
            if (source != null) {
                source.close();
            }
            if (destination != null) {
                destination.close();
            }
            masir = destinationFile.getName();
            sendToMedia(destinationFile, masir);
            masir = destinationFile.getAbsolutePath();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return masir;
    }

    // OK
    private void sendToMedia(File imageFile, String imageTitle){
        ContentValues image = new ContentValues();
        Date dateTaken = new Date();

        File parent = imageFile.getParentFile();
        String path = parent.toString().toLowerCase();
        String name = parent.getName().toLowerCase();

        image.put(MediaStore.Images.Media.TITLE, imageTitle);
        image.put(MediaStore.Images.Media.DISPLAY_NAME, String.format(this.getText(R.string.imageDisplayName).toString(),states.getKhas()));
        image.put(MediaStore.Images.Media.DESCRIPTION, String.format(this.getText(R.string.imageDescription).toString(),name));
        image.put(MediaStore.Images.Media.DATE_ADDED, dateTaken.toString());
        image.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken.toString());
        image.put(MediaStore.Images.Media.DATE_MODIFIED, dateTaken.toString());
        image.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
        image.put(MediaStore.Images.Media.ORIENTATION, orientation);//getImageOrientation(imageFile.getAbsolutePath()));

        image.put(MediaStore.Images.ImageColumns.BUCKET_ID, path.hashCode());
        image.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, name);
        image.put(MediaStore.Images.Media.SIZE, imageFile.length());
        image.put(MediaStore.Images.Media.DATA, imageFile.getAbsolutePath());

        this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image);
    }

    private void checkMultiplePermissions() {

        if (Build.VERSION.SDK_INT >= 23) {
            List<String> permissionsNeeded = new ArrayList<String>();
            List<String> permissionsList = new ArrayList<String>();

            if (!addPermission(permissionsList, android.Manifest.permission.ACCESS_FINE_LOCATION)) {
                permissionsNeeded.add("GPS");
            }

            if (!addPermission(permissionsList, android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
                permissionsNeeded.add("Read Storage");
            }

            if (permissionsList.size() > 0) {
                requestPermissions(permissionsList.toArray(new String[permissionsList.size()]),
                        REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                return;
            }
        }
    }

    private boolean addPermission(List<String> permissionsList, String permission) {
        try {
            if (Build.VERSION.SDK_INT >= 23)

                if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                    permissionsList.add(permission);

                    if (!shouldShowRequestPermissionRationale(permission))
                        return false;
                }
        } catch(Exception ex){
            ex.printStackTrace();
        }
        return true;
    }
}

But class addPermission raise error:

java.lang.NullPointerException: Attempt to invoke virtual method 'int android.content.Context.checkSelfPermission(java.lang.String)' on a null object reference

I think the way I call activity is not correct, but I have no idea how to do it, please help.

Edit: I have found this difference in returned path:

String image_path = cursor.getString(cursor.getColumnIndex("_data"));

The changed part is obvious:

old but correct path: /storage/emulated/0/DCIM/Camera/IMG_20161215_173334.jpg
new but incorrect path: /storage/3466-033/DCIM/Camera/IMG_20161215_173334.jpg

I think since new devices permit user to select where to save Images, then returning address is changed accordingly. How to get correct address out of cursor?

Ahmad Ebrahimi
  • 267
  • 5
  • 24

1 Answers1

0

You can't do that with a broadcast receiver. You can check if you have a permission via ContextCompat.checkSelfPermission, but in order to request the permission, you need to call ActivityCompat.requestPermissions. It needs an activity, and the result will also arrive to that activity.

Given that, the best solution for you is to implement some activity which will explain the user what is going on and request the permission. If the broadcast receiver detects that it doesn't have the necessary permission, it would launch this activity. When the permission is granted, the normal operation would be resumed.

I have to say that as a user it would be very weird to me if a dialog with a permission request suddenly popped up out of the blue, so I think it's for the best that you need to have an activity to request permissions.

Judging by your path, however, it is definitely somewhere on the SD card. This means that the SD card write restrictions apply. That means that requesting permissions for writing won't help. Take a look at this question: How to avoid the “EACCES permission denied” on SD card?

Community
  • 1
  • 1
Malcolm
  • 41,014
  • 11
  • 68
  • 91
  • You are right, normally in broadcastreceiver it is not possible to request for permission, though there is way to ask permission based on external activity,; but in this case when I check it says that it has permission, it says that sdcard is monted and I can write, also both source anddestination folder are the same. – Ahmad Ebrahimi Dec 14 '16 at 16:34
  • @AhmadEbrahimi Ah, so it's the SD card you are writing to. Then take a look at this question: [How to avoid the “EACCES permission denied” on SD card?](http://stackoverflow.com/questions/22406061/howto-avoid-the-eacces-permission-denied-on-sdcard-with-kitkat-4-4-2-version) – Malcolm Dec 14 '16 at 16:38
  • It sounds that I made a mistake: File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), masirFolder) this is not SdCard – Ahmad Ebrahimi Dec 14 '16 at 16:46
  • Since I want to rename it, certainly directory exist, also I am checking too. – Ahmad Ebrahimi Dec 14 '16 at 16:59
  • I am spending all day long to run again this code, just due to changes in Android 6. – Ahmad Ebrahimi Dec 14 '16 at 17:00
  • @AhmadEbrahimi Well, the only change in Android 6.0 is the runtime permissions, so either this means that the permission isn't actually granted, or this is not connected to Android 6.0. – Malcolm Dec 14 '16 at 17:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/130635/discussion-between-ahmad-ebrahimi-and-malcolm). – Ahmad Ebrahimi Dec 14 '16 at 19:54