在广播接收器上,检查写入权限android M

时间:2016-12-14 16:07:45

标签: android permissions broadcastreceiver runtime

我使用mediareceiver of media folder android.hardware.action.NEW_PICTURE服务来重命名并使用此代码移动图片并且它正在运行:

CameraReciver     包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();
    }

}

,这是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;
    }
}

但是类addPermission会引发错误:

  

java.lang.NullPointerException:尝试调用虚方法'int   android.content.Context.checkSelfPermission(java.lang.String)'上的一个   null对象引用

我认为我称之为活动的方式不正确,但我不知道该怎么做,请帮忙。

编辑: 我发现返回路径有这种差异:

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

改变的部分显而易见:

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

我认为,由于新设备允许用户选择保存图像的位置,因此返回地址会相应更改。 如何从光标中获取正确的地址?

1 个答案:

答案 0 :(得分:0)

你不能用广播接收器做到这一点。您可以通过ContextCompat.checkSelfPermission检查您是否拥有权限,但要申请权限,您需要致电ActivityCompat.requestPermissions。它需要一个活动,结果也会到达该活动。

鉴于此,对您而言,最佳解决方案是实施一些活动,该活动将向用户解释正在进行的操作并请求权限。如果广播接收器检测到它没有必要的许可,它将启动此活动。授予权限后,将恢复正常操作。

我必须说,作为一个用户,如果一个带有权限请求的对话框突然突然出现,那对我来说会很奇怪,所以我认为你需要有一个活动来请求权限才是最好的

然而,从您的路径来看,它绝对是SD卡上的某个地方。这意味着SD卡写入限制适用。这意味着请求写入权限将无济于事。看一下这个问题:How to avoid the “EACCES permission denied” on SD card