1 接收和发送短信
1.1 接收短信
思路:当手机收到一条短信,会发出一条广播,通过注册广播接收器得知,然后获取短信,显示。
1.1.1 Manifest.xml 注册:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
1.1.2 在布局文件我们简单用两个textView分别显示短信的发送者还有短信内容。在Activity文件中当然是获取实例然后setText()设置控件的内容。
Activity中我们定义一个内部类MessageReceiver继承BroadcastReceiver,在onReceive()里写获取短信内容的逻辑。
首先是获取一个Bundle,然后通过”pdus”键获得SMS pdus的数组,其中每一个pdu表示一条短信消息。接着使用SmsMessage的createFromPdu()方法把pdu字节数组转换为SmsMessage对象,调用其getOriginatingAddress()可获取发送号码,getMessageBody()可获取短信内容,把短信内容拼接起来就是一条完整信息啦。
最后显示在控件上就可以了。
class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object[] pdus = (Object[])bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
//String format = intent.getStringExtra("format");
for(int i=0; i<messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
String address = messages[0].getOriginatingAddress();
String fullMsg = "";
for(SmsMessage message: messages) {
fullMsg += message.getMessageBody();
}
tvFrom.setVisibility(View.VISIBLE);
tvMsg.setVisibility(View.VISIBLE);
sender.setText(address);
msg.setText(fullMsg);
}
}
1.1.3 当然还要注册这个接收器,使用动态注册
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//……
//接收短信
recvFilter = new IntentFilter();
recvFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
receiver = new MessageReceiver();
registerReceiver(receiver, recvFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
1.2 发送短信
1.2.1 Manifest.xml 注册
<uses-permission android:name="android.permission.SEND_SMS"/>
1.2.2 我们在布局文件简单设置两个EditText用于接收号码输入和短信内容输入,一个Button用于触发发送短信的逻辑。
在onClick()方法中,使用SmsManager的getDefault()方法获取一个smsManager实例,然后使用smsManager的sendTextMessage()方法就能发送短信了。
sendTextMessage()参数:
destinationAddress 发送短信的地址(也就是号码)
scAddress 短信服务中心,如果为null,就是用当前默认的短信服务中心
text 短信内容
sentIntent 如果不为null,当短信发送成功或者失败时,这个PendingIntent会被广播出去成功的结果代码是Activity.RESULT_OK,或者下面这些错误之一 :RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU
对于 RESULT_ERROR_GENERIC_FAILURE, 这个sentIntent可能包括额外的”errorCode”,包含一些具体有用的信息帮助检查 。基于SMS控制的全部程序检查,如果 sentIntent 为null,则发信程序会被所有位置程序检查一遍,这样会导致发送时间延长。
deliveryIntent 如果不为null,当这个短信发送到接收者那里,这个PendtingIntent会被广播,状态报告生成的pdu(指对等层次之间传递的数据单位)会拓展到数据(”pdu”)
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(
toer.getText().toString(), null,
toContent.getText().toString(), null, null);
}
});
1.2.3 基于以上,我们已经可以发送短信了。检查发送是否成功要借助第四个参数sentIntent
btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SmsManager smsManager = SmsManager.getDefault();
Intent sentIntent = new Intent("SENT_SMS_ACTION");
PendingIntent pi = PendingIntent.getBroadcast(
MainActivity.this, 0, sentIntent, 0);
smsManager.sendTextMessage(toer.getText().toString(), null,
toContent.getText().toString(), pi, null);
}
});
sendFilter = new IntentFilter();
sendFilter.addAction("SENT_SMS_ACTION");
sendReceiver = new SendStateReceiver();
registerReceiver(sendReceiver, sendFilter);
内部类SendStsteReceiver
class SendStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(getResultCode() == RESULT_OK) {
Toast.makeText(MainActivity.this, "Send succeeded", Toast.LENGTH_LONG).show();
}else {
Toast.makeText(MainActivity.this, "Send failed", Toast.LENGTH_LONG).show();
}
}
}
2 读取手机图片、调用摄像头拍照
2.1 调用手机摄像头
2.1.1 Manifest.xml 注册写入存储卡权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.1.2 我们在布局文件简单设置一个ImageView用于展示图片,一个Button用于调用摄像头,调用摄像头后还会进入裁剪程序,然后展示图片。
btnTakePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//new 一个新的文件对象,传入SD卡根目录,还有文件名称
File outputImg = new File(Environment.getExternalStorageDirectory(), "output_img.jpg");
try {
if (outputImg.exists()) {
outputImg.delete();
}
//根据抽象路径创建一个新的空文件
outputImg.createNewFile();
}catch (IOException e) {
e.printStackTrace();
}
//转换成Uri对象,代表图片的唯一地址
imgUri = Uri.fromFile(outputImg);
//调用相机程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);//指定输出地址
//这里使用的是带返回值的启动Activity的操作,这里传入的是自己定义的标识符,根据返回值进行不同的操作
startActivityForResult(intent, TAKE_PHOTO);
}
});
根据返回值进行不同的操作
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) { //就是我们调用时传进去的
case TAKE_PHOTO:
if(resultCode == RESULT_OK) { //拍照成功,调用裁剪程序
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imgUri, "image/*"); //设置数据和类型
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri); //设置输出路径
startActivityForResult(intent, CROP_PHOTO);
}
break;
case CROP_PHOTO:
if(resultCode == RESULT_OK) { //裁剪成功,展示图片
try {
Bitmap bitmap = BitmapFactory.decodeStream(
getContentResolver().openInputStream(imgUri));
picture.setImageBitmap(bitmap);
}catch (IOException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
2.2 调用相册选择手机图片
2.2.1 同样一个Button触发选择图片
btnChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO);
}
});
根据返回值进行不同操作
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO:
if(resultCode == RESULT_OK) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imgUri, "image/*");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
startActivityForResult(intent, CROP_PHOTO);
}
break;
case CROP_PHOTO:
if(resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(
getContentResolver().openInputStream(imgUri));
picture.setImageBitmap(bitmap);
}catch (IOException e) {
e.printStackTrace();
}
}
break;
case CHOOSE_PHOTO:
if(resultCode == RESULT_OK) {
//因为sdk19以后返回的数据不同,所以要根据手机系统版本进行不同的操作
//判断手机系统版本
if(Build.VERSION.SDK_INT >= 19) {
handleImageOnKiKai(data);
}else {
handleImageBeforeKiKai(data);
}
}
break;
default:
break;
}
}
不同SDK不同的操作:
//>=19的操作
@TargetApi(19)
private void handleImageOnKiKai(Intent data) {
String imagePath = null;
Uri uri = data.getData();
if(DocumentsContract.isDocumentUri(this, uri)) {
//如果是Document类型的Uri,则通过document id 处理
String docId = DocumentsContract.getDocumentId(uri);
if("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1];
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
}else if("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
imagePath = getImagePath(contentUri, null);
}else if("content".equalsIgnoreCase(uri.getScheme())) {
//不是document类型的Uri,普通方法处理
imagePath = getImagePath(uri, null);
}
displayImage(imagePath);
}
}
//<19的操作
private void handleImageBeforeKiKai(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
private String getImagePath(Uri uri, String selection) {
String path = null;
//通过Uri 和selection获取真正的图片路径
Cursor cursor = getContentResolver().query(
uri, null, selection, null, null);
if(cursor != null) {
if(cursor.moveToFirst()) {
path = cursor.getString(
cursor.getColumnIndex(MediaStore.Images.Media.DATA));
}
cursor.close();
}
return path;
}
private void displayImage(String path) {
if(path != null) {
Bitmap bitmap = BitmapFactory.decodeFile(path);
picture.setImageBitmap(bitmap);
}else {
Toast.makeText(this, "Load Failed", Toast.LENGTH_LONG).show();
}
}