Intent 常用场景 FileProvider 拍照 裁剪

Posted baiqiantao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Intent 常用场景 FileProvider 拍照 裁剪相关的知识,希望对你有一定的参考价值。

Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 [email protected]

Intent 常用场景 FileProvider 拍照 裁剪


目录

常用的 Intent 场景

拍照、选择照片、裁剪照片

涉及到的权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>

需要配置 FileProvider

在清单文件中声明FileProvider:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
</provider>

res/xml/下添加file_paths.xml配置文件

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path
        name="files"
        path="/"/>
    <cache-path
        name="cache"
        path="/"/>
    <external-path
        name="external"
        path="/"/>
    <external-files-path
        name="external_file_path"
        path="/"/>
    <external-cache-path
        name="external_cache_path"
        path="/"/>
    <!--<external-media-path
        name="external-media-path"
        path=""/>-->
</paths>

Activity

public class MainActivity extends ListActivity {
    public static final String PATH = Environment.getExternalStorageDirectory().getPath() + File.separator;
    public static final String SAVE_FILE_NAME = "savePic.png";
    public static final String CROP_FILE_NAME = "cropPic.png";

    public static final int REQUEST_CODE_GET_IMG = 1;
    public static final int REQUEST_CODE_SAVE_IMG = 2;
    public static final int REQUEST_CODE_PICK_IMG = 3;

    public static final int REQUEST_CODE_CROP_FALSE = 4;
    public static final int REQUEST_CODE_CROP_TRUE = 5;

    public static final int REQUEST_CODE_PICK_CROP_TRUE = 6;

    private ImageView imageView;
    private File saveFile;
    private File cropFile;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] array = {
            "调用系统相机拍照,并返回拍摄的照片,获取的是裁剪后的小图",
            "调用系统相机拍照,并保存照片到指定位置,保存的为原图",
            "调用图库获取照片,并返回选择的照片",
            "调用图库裁剪照片,并保存照片到指定位置",
            "调用图库裁剪照片,并返回裁剪后的照片,不保证一定能成功",
            "调用图库获取照片,并返回选择的照片,然后调用图库裁剪照片,并保存照片到指定位置",};
        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, Arrays.asList(array)));
        imageView = new ImageView(this);
        getListView().addFooterView(imageView);

        saveFile = new File(PATH + SAVE_FILE_NAME);
        cropFile = new File(PATH + CROP_FILE_NAME);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
            case 0://调用系统相机拍照,并返回拍摄的照片,获取的是裁剪后的小图
                Intent getCameraPicIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(getCameraPicIntent, REQUEST_CODE_GET_IMG);
                break;
            case 1://调用系统相机拍照,并保存照片到指定位置,保存的为原图
                Uri saveUri = Utils.getFileUri(this, saveFile);
                Intent saveCameraPicIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                saveCameraPicIntent.putExtra(MediaStore.EXTRA_OUTPUT, saveUri);
                startActivityForResult(saveCameraPicIntent, REQUEST_CODE_SAVE_IMG);
                break;
            case 2: //调用图库获取照片,并返回选择的照片
                Intent pickIntent = new Intent(Intent.ACTION_PICK);
                pickIntent.setType("image/*");
                startActivityForResult(pickIntent, REQUEST_CODE_PICK_IMG);
                break;
            case 3: //调用图库裁剪照片,并保存照片到指定位置
                Uri dataUri = Utils.getFileUri(this, saveFile);
                Intent cropPicIntent = Utils.getCropImageNotReturnDataIntent(dataUri, 400, 400, cropFile);
                startActivityForResult(cropPicIntent, REQUEST_CODE_CROP_FALSE);
                break;
            case 4: //调用图库裁剪照片,并返回裁剪后的照片,不保证一定能成功,特别是大于 200 *200 时通常都会失败
                Intent cropPicIntent2 = Utils.getCropImageReturnDataIntent(Utils.getFileUri(this, saveFile), 200, 200);
                startActivityForResult(cropPicIntent2, REQUEST_CODE_CROP_TRUE);
                break;
            case 5: //调用图库获取照片,并返回选择的照片,然后调用图库裁剪照片,并保存照片到指定位置
                Intent intent = new Intent(Intent.ACTION_PICK);
                intent.setType("image/*");
                startActivityForResult(intent, REQUEST_CODE_PICK_CROP_TRUE);
                break;
            default:
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) {
            Toast.makeText(this, "没有成功返回", Toast.LENGTH_SHORT).show();
            return;
        }
        switch (requestCode) {
            case REQUEST_CODE_GET_IMG://调用系统相机拍照,并返回拍摄的照片,获取的是裁剪后的小图
                if (data != null && data.getExtras() != null) {
                    Bitmap dataBitmap = (Bitmap) data.getExtras().get("data");// 注意,拍摄的照片会自动进行压缩,且会压缩的非常非常小!
                    if (dataBitmap != null) {
                        imageView.setImageBitmap(dataBitmap);//返回的是Bitmap,因为有大小限制,所以会压缩
                        showToast("尺寸为" + dataBitmap.getWidth() + " * " + dataBitmap.getHeight()); //188 * 252
                    }
                }
                break;
            case REQUEST_CODE_SAVE_IMG://调用系统相机拍照,并保存照片到指定位置,保存的为原图
                showToast("照片已保存到指定的Uri中");//注意,由于数据已保存到Uri中,所以这里返回的 data 为 null
                imageView.setImageBitmap(BitmapFactory.decodeFile(saveFile.getAbsolutePath()));
                break;
            case REQUEST_CODE_PICK_IMG://调用图库获取照片,并返回选择的照片
                if (data != null && data.getData() != null) {
                    showToast("选择的照片:" + data.getData().toString());//【content://media/external/images/media/247778】
                    imageView.setImageURI(data.getData());
                }
                break;
            case REQUEST_CODE_CROP_FALSE: //调用图库裁剪照片,并保存照片到指定位置
                showToast("剪切后的照片已保存到指定的Uri中");
                imageView.setImageBitmap(BitmapFactory.decodeFile(cropFile.getAbsolutePath()));
                break;
            case REQUEST_CODE_CROP_TRUE: //调用图库裁剪照片,并返回裁剪后的照片,不保证一定能成功
                if (data != null) {
                    Bitmap cropBitmap = data.getParcelableExtra("data");
                    if (cropBitmap != null) {
                        imageView.setImageBitmap(cropBitmap);
                        showToast("尺寸为" + cropBitmap.getWidth() + " * " + cropBitmap.getHeight());
                    }
                }
                break;
            case REQUEST_CODE_PICK_CROP_TRUE://调用图库获取照片,并返回选择的照片,然后调用图库裁剪照片,并保存照片到指定位置
                if (data != null && data.getData() != null) {
                    Intent cropPicIntent = Utils.getCropImageNotReturnDataIntent(data.getData(), 400, 400, cropFile);
                    startActivityForResult(cropPicIntent, REQUEST_CODE_CROP_FALSE);
                }
                break;
            default:
                break;
        }
    }

    private void showToast(String text) {
        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
    }
}

工具类

public class Utils {
    public static Uri getFileUri(Context context, File saveFile) {
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            String authority = context.getPackageName() + ".fileprovider"; //【清单文件中provider的authorities属性的值】
            uri = FileProvider.getUriForFile(context, authority, saveFile);
        } else {
            uri = Uri.fromFile(saveFile);
        }
        Log.i("bqt", "【uri】" + uri);//【content://{$authority}/files/bqt/temp】或【file:///storage/emulated/0/bqt/temp】
        return uri;
    }

    /**
     * 调出图库APP的裁剪图片功能,将指定Uri中的图片裁剪为指定大小,裁剪的图片会在 onActivityResult 中的 intent 中返回
     * 经过测试发现,这种方式在 7.0 之后不能用了!
     */
    public static Intent getCropImageReturnDataIntent(Uri dataUri, int desWidth, int desHeight) {
        Intent intent = getCropImageIntent(dataUri, desWidth, desHeight);
        //设置为true时,裁剪的图片不会在给定的 uri 中返回,而会在 onActivityResult 中的 intent 中返回
        intent.putExtra("return-data", true);
        return intent;
    }

    /**
     * 调出图库APP的裁剪图片功能,将指定Uri中的图片裁剪为指定大小,裁剪的图片会保存到指定的 uri 中
     */
    public static Intent getCropImageNotReturnDataIntent(Uri dataUri, int desWidth, int desHeight, File cropFile) {
        Intent intent = getCropImageIntent(dataUri, desWidth, desHeight);
        //设置为false时,裁剪的图片会保存到指定的 uri 中,而不会在 onActivityResult 中的 intent 中返回
        intent.putExtra("return-data", false);
        // 注意:若裁减时打开图片的 uri 与保存图片的 uri 相同,会产生冲突,导致裁减完成后图片的大小变成0Byte
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cropFile));
        return intent;
    }

    private static Intent getCropImageIntent(Uri dataUri, int desWidth, int desHeight) {
        Intent intent = new Intent("com.android.camera.action.CROP");//指定action是使用系统图库裁剪图片
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //必须加这个临时权限
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        intent.setDataAndType(dataUri, "image/*");
        intent.putExtra("crop", "true");//可裁剪
        intent.putExtra("aspectX", 1);//设置裁剪比例及裁剪图片的具体宽高
        intent.putExtra("aspectY", 1);
        intent.putExtra("outputX", desWidth);
        intent.putExtra("outputY", desHeight);
        intent.putExtra("scale", true);//设置是否允许拉伸
        intent.putExtra("scaleUpIfNeeded", true);//没什么作用
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());//设置输出格式
        intent.putExtra("noFaceDetection", true);//设置是否需要人脸识别
        return intent;
    }
}

其他简单场景

拨打电话

intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:10086"));//打开系统默认拨号程序,不需要权限
intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:10000"));//直接呼叫号码,权限:CALL_PHONE
startActivity(intent);

发送短信

Uri uri = Uri.parse("smsto:10086");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
intent.putExtra("sms_body", "Hello");
startActivity(intent);

发送彩信

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra("sms_body", "Hello");
Uri uri = Uri.parse("content://media/external/images/media/23");//或Uri.parse("file:///sdcard/a.png")
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType("image/png");
startActivity(intent);

打开浏览器

Uri uri = Uri.parse("http://www.baidu.com");
Intent intent  = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

打开浏览器并搜索内容

Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"searchString");//通过浏览器默认搜索引擎搜索内容
startActivity(intent);

发邮件

使用默认邮件应用的默认账户发邮件

Uri uri = Uri.parse("mailto:[email protected]");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(intent);

详细设置

Intent intent=new Intent(Intent.ACTION_SEND);
String[] tos = {"[email protected]", "[email protected]"}; 
String[] ccs = {"[email protected]", "[email protected]"};
String[] bccs = {"[email protected]", "[email protected]"}; 
intent.putExtra(Intent.EXTRA_EMAIL, tos);// 收件人
intent.putExtra(Intent.EXTRA_CC, ccs); // 抄送
intent.putExtra(Intent.EXTRA_BCC, bccs);// 密送
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");//主题
intent.putExtra(Intent.EXTRA_TEXT, "Hello");//内容
intent.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/eoe.mp3");//附件
intent.setType("message/rfc822"); //或 "text/plain" 或 "audio/mp3"
startActivity(intent);

打开地图并定位到指定位置

Uri uri = Uri.parse("geo:39.9,116.3");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

路径规划

Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=39.9 116.3&daddr=31.2 121.4");//从A地到B地
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

多媒体播放

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/foo.mp3");
intent.setDataAndType(uri, "audio/mp3");//类型Type可以指定为 audio/x-mpeg ,或者不指定也行
startActivity(intent);

获取SD卡下所有音频文件,然后播放第一首

Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

打开应用在应用市场的详情页

Uri uri = Uri.parse("market://details?id=" + "包名"); //搜索应用为 Uri.parse("market://search?q=pname:包名");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);

进入手机设置界面

Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
startActivityForResult(intent, 0);

安装和卸载 apk

安装 apk

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + path + "a.apk"), "application/vnd.android.package-archive");
startActivity(intent);

卸载apk

Uri uri = Uri.fromParts("package", strPackageName, null);
Intent it = new Intent(Intent.ACTION_DELETE, uri);
startActivity(it);

查看指定联系人

Uri personUri = ;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(ContentUris.withAppendedId(People.CONTENT_URI, info.id));//联系人ID
startActivity(intent);

调用系统编辑添加联系人

Intent it = newIntent(Intent.ACTION_INSERT_OR_EDIT);    
it.setType(Contacts.CONTENT_ITEM_TYPE);
it.putExtra(Contacts.Intents.Insert.NAME, "My Name");
it.putExtra(Contacts.Intents.Insert.COMPANY, "organization");    
it.putExtra(Contacts.Intents.Insert.EMAIL,"email");    
it.putExtra(Contacts.Intents.Insert.EMAIL_TYPE, Contacts.ContactMethodsColumns.TYPE_WORK);    
it.putExtra(Contacts.Intents.Insert.PHONE,"homePhone");    
it.putExtra(Contacts.Intents.Insert.PHONE_TYPE,Contacts.PhonesColumns.TYPE_MOBILE);    
it.putExtra(Contacts.Intents.Insert.SECONDARY_PHONE,"mobilePhone");    
it.putExtra(Contacts.Intents.Insert.TERTIARY_PHONE,"workPhone");    
it.putExtra(Contacts.Intents.Insert.JOB_TITLE,"title");    
startActivity(it);

打开另一程序

Intent intent = new Intent();
intent.setComponent(new ComponentName(context.getPackageName(), "com.xiaomi.mipushdemo.MainActivity"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//intent.setAction("android.intent.action.MAIN");
startActivity(intent);

方式2

boolean exists =new File("/data/data/" + "包名").exists();//判断是否安装目标应用
if (exists) {
    Intent intent = getPackageManager().getLaunchIntentForPackage("包名");
    startActivity(intent);
}

强制和某QQ聊天

String qqNo = "909120849";
String qqUri = "mqqwpa://im/chat?chat_type=wpa&uin=" + qqNo + "&version=1";
Uri uri = Uri.parse(qqUri);
intent = new Intent(Intent.ACTION_VIEW, uri);//跳转到QQ,并直接进入到和指定QQ号码聊天的界面,且可以是陌生人的QQ号
startActivity(intent);

打开录音机

Intent mi = new Intent(Media.RECORD_SOUND_ACTION);
startActivity(mi);

2018-11-17

























以上是关于Intent 常用场景 FileProvider 拍照 裁剪的主要内容,如果未能解决你的问题,请参考以下文章

Android FileProvider特性与Intent重定向漏洞

Android FileProvider特性与Intent重定向漏洞

FileProvider 添加二级目录

Android Intent FileProvider“权限被拒绝”在谷歌地球中打开KML文件?

读取由FileProvider创建的Uri路径文件

ShareCompat.IntentBuilder:与收件人混合的Intent.data