1.添加联系人


package com.tiger.chapter07_client;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.view.View;
import android.widget.EditText;
import com.tiger.chapter07_client.entity.Contact;
import java.util.ArrayList;
public class ContactAddActivity extends AppCompatActivity implements View.OnClickListener {
private EditText et_contact_name;
private EditText et_contact_phone;
private EditText et_contact_email;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_add);
et_contact_name = findViewById(R.id.et_contact_name);
et_contact_phone = findViewById(R.id.et_contact_phone);
et_contact_email = findViewById(R.id.et_contact_email);
findViewById(R.id.btn_add_contact).setOnClickListener(this);
findViewById(R.id.btn_read_contact).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_add_contact) {
//创建一个联系人对象
Contact contact = new Contact();
contact.name = et_contact_name.getText().toString().trim();
contact.phone = et_contact_phone.getText().toString().trim();
contact.email = et_contact_email.getText().toString().trim();
//方式一,使用ContentResolver多次写入,每次一个字段
// addContacts(getContentResolver(),contact);
//方式二 批处理方式
// 每一次操作都是一个 ContentProviderOperation, 构建一个操作集合,然后一次性执行
//好处是,要么全部成功, 要么全部失败,保证了事务的一致性
addFullContacts(getContentResolver(),contact);
} else {
}
}
//往手机通讯录一次性添加一个联系人信息(包括主记录、姓名、电话号码、电子邮箱)
private void addFullContacts(ContentResolver resolver, Contact contact) {
// 创建一个插入联系人主记录的内容操作器
ContentProviderOperation op_main = ContentProviderOperation
.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build();
// 创建一个插入联系人姓名记录的内容操作器
ContentProviderOperation op_name = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI)
// 将第0个操作的id,即 raw_contacts 的 id 作为 data 表中的 raw_contact_id
.withValueBackReference(ContactsContract.Contacts.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.Contacts.Data.DATA2, contact.name)
.build();
// 创建一个插入联系人电话号码记录的内容操作器
ContentProviderOperation op_phone = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI)
// 将第0个操作的id,即 raw_contacts 的 id 作为 data 表中的 raw_contact_id
.withValueBackReference(ContactsContract.Contacts.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.Contacts.Data.DATA1, contact.phone)
.withValue(ContactsContract.Contacts.Data.DATA2, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
.build();
// 创建一个插入联系人电子邮箱记录的内容操作器
ContentProviderOperation op_email = ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI)
// 将第0个操作的id,即 raw_contacts 的 id 作为 data 表中的 raw_contact_id
.withValueBackReference(ContactsContract.Contacts.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.Contacts.Data.DATA1, contact.email)
.withValue(ContactsContract.Contacts.Data.DATA2, ContactsContract.CommonDataKinds.Email.TYPE_WORK)
.build();
// 声明一个内容操作器的列表,并将上面四个操作器添加到该列表中
ArrayList<ContentProviderOperation> operations = new ArrayList<>();
operations.add(op_main);
operations.add(op_name);
operations.add(op_phone);
operations.add(op_email);
try {
// 批量提交四个操作
resolver.applyBatch(ContactsContract.AUTHORITY, operations);
} catch (OperationApplicationException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
//往手机通讯录添加一个联系人信息(包括姓名,电话号码,电子邮箱)
private void addContacts(ContentResolver resolver, Contact contact) {
ContentValues values = new ContentValues();
//往 raw_contacts 添加联系人记录,并获取添加后的联系人编号
Uri uri = resolver.insert(ContactsContract.RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(uri);
ContentValues name = new ContentValues();
//关联联系人编号
name.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID,rawContactId);
//"姓名” 的数据类型
name.put(ContactsContract.Contacts.Data.MIMETYPE,ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
// 联系人的姓名
name.put(ContactsContract.Contacts.Data.DATA2,contact.name);
resolver.insert(ContactsContract.Data.CONTENT_URI,name);
ContentValues phone = new ContentValues();
//关联联系人编号
phone.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID,rawContactId);
//"电话” 的数据类型
phone.put(ContactsContract.Contacts.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
// 联系人的电话号码
//联系类型 1表示家庭 2表示工作
phone.put(ContactsContract.Contacts.Data.DATA1,contact.phone);
phone.put(ContactsContract.Contacts.Data.DATA2, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
//往提供器添加联系人的姓名记录
resolver.insert(ContactsContract.Data.CONTENT_URI,phone);
ContentValues email = new ContentValues();
//关联联系人编号
email.put(ContactsContract.Contacts.Data.RAW_CONTACT_ID,rawContactId);
//"电子邮箱” 的数据类型
email.put(ContactsContract.Contacts.Data.MIMETYPE,ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
// 联系人的电话号码
//联系类型 1表示家庭 2表示工作
email.put(ContactsContract.Contacts.Data.DATA1,contact.email);
email.put(ContactsContract.Contacts.Data.DATA2, ContactsContract.CommonDataKinds.Email.TYPE_WORK);
//往提供器添加联系人的姓名记录
resolver.insert(ContactsContract.Data.CONTENT_URI,email);
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_contact_name"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="联系人姓名:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_contact_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:gravity="start|center"
android:hint="请输入联系人姓名"
android:inputType="text"
android:maxLength="12"
android:text="Jack"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_contact_phone"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="联系人号码:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_contact_phone"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:gravity="start|center"
android:hint="请输入联系人手机号码"
android:inputType="number"
android:maxLength="11"
android:text="13612345678"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_contact_email"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="联系人邮箱:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_contact_email"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:gravity="start|center"
android:hint="请输入联系人邮箱"
android:inputType="textEmailAddress"
android:text="18977778888@qq.com"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
<Button
android:id="@+id/btn_add_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="添加联系人"
android:textColor="@color/black"
android:textSize="17sp" />
<Button
android:id="@+id/btn_read_contact"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="查询联系人"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
2.查询联系人
// 查询通讯录信息
@SuppressLint("Range")
private void readPhoneContacts(ContentResolver resolver) {
// 先查询 raw_contacts 表,在根据 raw_contacts_id 去查询 data 表
Cursor cursor = resolver.query(ContactsContract.RawContacts.CONTENT_URI, new String[]{ContactsContract.RawContacts._ID}, null, null, null, null);
while (cursor.moveToNext()) {
int rawContactId = cursor.getInt(0);
Uri uri = Uri.parse("content://com.android.contacts/contacts/" + rawContactId + "/data");
Cursor dataCursor = resolver.query(uri, new String[]{ContactsContract.Contacts.Data.MIMETYPE, ContactsContract.Contacts.Data.DATA1, ContactsContract.Contacts.Data.DATA2},
null, null, null);
Contact contact = new Contact();
while (dataCursor.moveToNext()) {
String data1 = dataCursor.getString(dataCursor.getColumnIndex(ContactsContract.Contacts.Data.DATA1));
String mimeType = dataCursor.getString(dataCursor.getColumnIndex(ContactsContract.Contacts.Data.MIMETYPE));
switch (mimeType) {
//是姓名
case ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
contact.name = data1;
break;
//邮箱
case ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE:
contact.email = data1;
break;
//手机
case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
contact.phone = data1;
break;
}
}
dataCursor.close();
// RawContacts 表中出现的 _id,不一定在 Data 表中都会有对应记录
if (contact.name != null) {
Log.d("ning", contact.toString());
}
}
cursor.close();
}
3.监听短信

package com.tiger.chapter07_client;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
public class MonitorSmsActivity extends AppCompatActivity {
private SmsGetObserver mObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_monitor_sms);
// 给指定Uri注册内容观察器,一旦发生数据变化,就触发观察器的onChange方法
Uri uri = Uri.parse("content://sms");
// notifyForDescendents:
// false :表示精确匹配,即只匹配该Uri,true :表示可以同时匹配其派生的Uri
// 假设UriMatcher 里注册的Uri共有一下类型:
// 1.content://AUTHORITIES/table
// 2.content://AUTHORITIES/table/#
// 3.content://AUTHORITIES/table/subtable
// 假设我们当前需要观察的Uri为content://AUTHORITIES/student:
// 如果发生数据变化的 Uri 为 3。
// 当notifyForDescendents为false,那么该ContentObserver会监听不到,但是当notifyForDescendents 为ture,能捕捉该Uri的数据库变化。
mObserver = new SmsGetObserver(this);
getContentResolver().registerContentObserver(uri, true, mObserver);
}
@Override
protected void onDestroy() {
super.onDestroy();
getContentResolver().unregisterContentObserver(mObserver);
}
private static class SmsGetObserver extends ContentObserver {
private final Context mContext;
public SmsGetObserver(Context context) {
super(new Handler(Looper.getMainLooper()));
this.mContext = context;
}
@SuppressLint("Range")
@Override
public void onChange(boolean selfChange, @Nullable Uri uri) {
super.onChange(selfChange, uri);
// onChange会多次调用,收到一条短信会调用两次onChange
// mUri===content://sms/raw/20
// mUri===content://sms/inbox/20
// 安卓7.0以上系统,点击标记为已读,也会调用一次
// mUri===content://sms
// 收到一条短信都是uri后面都会有确定的一个数字,对应数据库的_id,比如上面的20
if (uri == null) {
return;
}
if (uri.toString().contains("content://sms/raw") ||
uri.toString().equals("content://sms")) {
return;
}
// 通过内容解析器获取符合条件的结果集游标
Cursor cursor = mContext.getContentResolver().query(uri, new String[]{"address", "body", "date"}, null, null, "date DESC");
if (cursor.moveToNext()) {
// 短信的发送号码
String sender = cursor.getString(cursor.getColumnIndex("address"));
// 短信内容
String content = cursor.getString(cursor.getColumnIndex("body"));
Log.d("ning", String.format("sender:%s,content:%s", sender, content));
}
cursor.close();
}
}
}
如果向自己向监听器发送消息就用这个
4.选择图片与发送彩信
package com.tiger.chapter07_client;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import com.tiger.chapter07_client.utils.ToastUtlis;
public class SendMmsActivity extends AppCompatActivity implements View.OnClickListener {
private ImageView iv_appendix;
private ActivityResultLauncher<Intent> mResultLauncher;
private EditText et_phone;
private EditText et_title;
private EditText et_message;
private Uri picUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send_mms);
et_phone = findViewById(R.id.et_phone);
et_title = findViewById(R.id.et_title);
et_message = findViewById(R.id.et_message);
iv_appendix = findViewById(R.id.iv_appendix);
iv_appendix.setOnClickListener(this);
findViewById(R.id.btn_send_mms).setOnClickListener(this);
// 跳转到系统相册,选择图片,并返回
mResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == RESULT_OK) {
Intent intent = result.getData();
// 获得选中图片的路径对象
// content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fting2.jpg
picUri = intent.getData();
if (picUri != null) {
// ImageView 显示刚刚选中的图片
iv_appendix.setImageURI(picUri);
Log.d("ning", "picUri:" + picUri.toString());
}
}
}
});
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.iv_appendix) {
// 跳转到系统相册,选择图片,并返回
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// 设置内容类型为图片类型
intent.setType("image/*");
// 打开系统相册,并等待图片选择结果
mResultLauncher.launch(intent);
} else if (v.getId() == R.id.btn_send_mms) {
// 发送带图片的彩信
sendMms(et_phone.getText().toString(),
et_title.getText().toString(),
et_message.getText().toString());
}
}
// 发送带图片的彩信
private void sendMms(String phone, String title, String message) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Intent 的接受者将被准许读取Intent 携带的URI数据
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// 彩信发送的目标号码
intent.putExtra("address", phone);
// 彩信的标题
intent.putExtra("subject", title);
// 彩信的内容
intent.putExtra("sms_body", message);
// 彩信的图片附件
intent.putExtra(Intent.EXTRA_STREAM, picUri);
// 彩信的附件为图片
intent.setType("image/*");
// 因为未指定要打开哪个页面,所以系统会在底部弹出选择窗口
startActivity(intent);
ToastUtlis.show(this, "请在弹窗中选择短信或者信息应用");
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="对方号码:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_phone"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:inputType="number"
android:textColor="@color/black"
android:textSize="17sp"
android:text="10086"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="彩信标题:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:textColor="@color/black"
android:textSize="17sp"
android:text="hallo" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="彩信内容:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_message"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:gravity="left|top"
android:textColor="@color/black"
android:textSize="17sp"
android:text="test"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top|center"
android:text="图片附件:"
android:textColor="@color/black"
android:textSize="17sp" />
<ImageView
android:id="@+id/iv_appendix"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:scaleType="fitStart"
android:src="@drawable/add_pic" />
</LinearLayout>
<Button
android:id="@+id/btn_send_mms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="发送彩信"
android:textColor="@color/black"
android:textSize="17sp" />
</LinearLayout>
5.通过MediaStore 查询图片 然后通过 FileProvider 来获取图片发送彩信

1.Activity
package com.tiger.chapter07_client;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.GridLayout;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import com.tiger.chapter07_client.entity.ImageInfo;
import com.tiger.chapter07_client.utils.PermissionUtil;
import com.tiger.chapter07_client.utils.ToastUtlis;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ProviderMmsActivity extends AppCompatActivity {
private static final String[] PERMISSIONS = new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE
};
private static final int PERMISSION_REQUEST_CODE = 1;
private List<ImageInfo> mImageList = new ArrayList<>();
private GridLayout gl_appendix;
private EditText et_phone;
private EditText et_title;
private EditText et_message;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_provider_mms);
et_phone = findViewById(R.id.et_phone);
et_title = findViewById(R.id.et_title);
et_message = findViewById(R.id.et_message);
gl_appendix = findViewById(R.id.gl_appendix);
//手动让MediaStore扫描入库
MediaScannerConnection.scanFile(this,
new String[]{Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()},
null, null);
if (PermissionUtil.checkPermission(this, PERMISSIONS, PERMISSION_REQUEST_CODE)) {
// 加载图片列表
loadImageList();
// 显示图像网格
showImageGrid();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE &&
PermissionUtil.checkGrant(grantResults)) {
// 加载图片列表
loadImageList();
// 显示图像网格
showImageGrid();
}else {
//可以选择在这里跳到设置页面开启权限
}
}
// 显示图像网格
private void showImageGrid() {
gl_appendix.removeAllViews();
for (ImageInfo image : mImageList) {
// image -> ImageView
ImageView iv_appendix = new ImageView(this);
Bitmap bitmap = BitmapFactory.decodeFile(image.path);
iv_appendix.setImageBitmap(bitmap);
// 设置图像视图的缩放类型
iv_appendix.setScaleType(ImageView.ScaleType.FIT_CENTER);
// 设置图像视图的布局参数
int px = Utils.dip2px(this, 110);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(px, px);
iv_appendix.setLayoutParams(params);
// 设置图像视图的内部间距
int padding = Utils.dip2px(this, 5);
iv_appendix.setPadding(padding, padding, padding, padding);
iv_appendix.setOnClickListener(v -> {
sendMms(et_phone.getText().toString(),
et_title.getText().toString(),
et_message.getText().toString(),
image.path);
});
// 把图像视图添加至网格布局
gl_appendix.addView(iv_appendix);
}
}
// 加载图片列表
@SuppressLint({"Range", "SuspiciousIndentation"})
private void loadImageList() {
//MediaStore
String[] columns = new String[]{
MediaStore.Images.Media._ID, // 编号
MediaStore.Images.Media.TITLE, // 标题
MediaStore.Images.Media.SIZE,// 文件大小
MediaStore.Images.Media.DATA,// 文件路径
};
// 图片大小在300KB以内
Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
columns,
"_size < 307200",
null,
"_size DESC"
);
int count = 0;
if (cursor != null) {
while (cursor.moveToNext() && count < 6) {
ImageInfo image = new ImageInfo();
image.id = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID));
image.name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.TITLE));
image.size = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.SIZE));
image.path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
if (FileUtil.checkFileUri(this, image.path)) {
count++;
mImageList.add(image);
}
Log.d("ning", "image:" + image.toString());
}
}
}
// 发送带图片的彩信
private void sendMms(String phone, String title, String message, String path) {
// 根据指定路径创建一个Uri对象
Uri uri = Uri.parse(path);
// 兼容Android7.0,把访问文件的Uri方式改为FileProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 通过FileProvider获得文件的Uri访问方式
//从图库传过来的图片也是FileProvider形式的 这就是第三方应用 给外界应用开放的一个 访问的一个接口 读取 图片
uri = FileProvider.getUriForFile(this, getString(R.string.file_provider), new File(path));
Log.d("ning", String.format("new uri:%s", uri.toString()));
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Intent 的接受者将被准许读取Intent 携带的URI数据
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// 彩信发送的目标号码
intent.putExtra("address", phone);
// 彩信的标题
intent.putExtra("subject", title);
// 彩信的内容
intent.putExtra("sms_body", message);
// 彩信的图片附件
intent.putExtra(Intent.EXTRA_STREAM, uri);
// 彩信的附件为图片
intent.setType("image/*");
// 因为未指定要打开哪个页面,所以系统会在底部弹出选择窗口
startActivity(intent);
ToastUtlis.show(this, "请在弹窗中选择短信或者信息应用");
}
}
2.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="对方号码:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_phone"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:inputType="number"
android:textColor="@color/black"
android:textSize="17sp"
android:text="10086"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="彩信标题:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:textColor="@color/black"
android:textSize="17sp"
android:text="Hallo"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="彩信内容:"
android:textColor="@color/black"
android:textSize="17sp" />
<EditText
android:id="@+id/et_message"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="3dp"
android:layout_weight="1"
android:background="@drawable/editext_selector"
android:gravity="left|top"
android:textColor="@color/black"
android:textSize="17sp"
android:text="test"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:text="点击下方图片开始发送彩信"
android:textColor="@color/black"
android:textSize="17sp" />
<GridLayout
android:id="@+id/gl_appendix"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="3" />
</LinearLayout>


3.AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 需要这个防止手机没有打电话功能 -->
<uses-feature
android:name="android.hardware.telephony"
android:required="false" /> <!-- 处于安全考虑 Android 11 要求应用事先说明需要访问的其他软件包 -->
<queries>
<!-- <package android:name="com.tiger.chapter07_server"/> -->
<provider android:authorities="com.tiger.chapter07_server.provider.UserInfoProvider" />
</queries>
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<!-- 在api 33版本及以上,READ_EXTERNAL_STORAGE失效了,要使用READ_MEDIA_IMAGES-->
<!-- 读取外部存储权限-->
<!-- 注意:安卓10以上无法显示图像,还需要在清单应用下面增加android:requestLegacyExternalStorage="true" -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication">
<activity
android:name=".ProviderMmsActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 用系统的 provider 为第三方应用提供接口获取图片-->
<!-- android:grantUriPermissions="true" -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="@string/file_provider"
android:grantUriPermissions="true">
<!-- 配置哪些路径是可以通过FileProvider访问的 -->
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>
4.FileUtils
// 检查文件是否存在,以及文件路径是否合法
public static boolean checkFileUri(Context ctx, String path) {
File file = new File(path);
Log.d("ning", "old path:" + path);
if (!file.exists() || !file.isFile() || file.length() <= 0) {
return false;
}
try {
// 检测文件路径是否支持 FileProvider 访问方式,如果发生异常,说明不支持
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(ctx, ctx.getString(R.string.file_provider), file);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
5.PermissionUtil
package com.tiger.chapter07_client.utils;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class PermissionUtil {
//检查多个权限。返回true表示已完全启用权限,返回false 表示 未完全启用权限
public static boolean checkPermission(Activity act, String[] permissions, int requestCode) {
//Android 6.0之后开始采用动态权限管理
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int check = PackageManager.PERMISSION_GRANTED;
for (String permission : permissions) {
check = ContextCompat.checkSelfPermission(act, permission);
if (check != PackageManager.PERMISSION_GRANTED) {
break;
}
}
//未开启该权限,则请求系统弹窗,好让用户选择 是否立即开启权限
if (check != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(act, permissions, requestCode);
return false;
}
}
return true;
}
public static boolean checkGrant(int[] grantResults) {
if (grantResults != null) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
} else {
return false;
}
}
}
8903

被折叠的 条评论
为什么被折叠?



