Android多媒体与通信功能开发实用指南
1. 多媒体处理
1.1 EXIF数据处理
EXIF数据可存储照片的多种元数据,包含日期时间、相机设置(如品牌和型号)、图像设置(如光圈和快门速度)、图像描述和位置等。
读取EXIF属性,可调用ExifInterface对象的getAttribute方法,并传入要读取的属性名称。ExifInterface类包含许多静态的TAG_*常量,可用于访问常见的EXIF元数据。修改EXIF属性,可使用setAttribute方法,传入要读取的属性名称和要设置的值。
以下代码展示了如何从SD卡上存储的文件中读取位置坐标和相机型号,并修改相机制造商详细信息:
File file = new File(Environment.getExternalStorageDirectory(),
"test.jpg");
try {
ExifInterface exif = new ExifInterface(file.getCanonicalPath());
// Read the camera model and location attributes
String model = exif.getAttribute(ExifInterface.TAG_MODEL);
float[] latLng = new float[2];
exif.getLatLong(latLng);
// Set the camera make
exif.setAttribute(ExifInterface.TAG_MAKE, "My Phone");
} catch (IOException e) {
Log.d("EXIF", e.getMessage());
}
1.2 向媒体库添加新媒体
默认情况下,应用程序创建的媒体文件其他应用无法访问。因此,将其插入媒体库是个好做法,这样其他应用就能访问了。
Android提供了两种将媒体插入媒体库的方法:
-
使用媒体扫描器
:MediaScannerConnection类提供了一种简单的方法,无需为媒体库内容提供者构建完整记录,就能将新媒体添加到媒体库。在使用scanFile方法对文件进行内容扫描之前,必须调用connect方法并等待与媒体扫描器的连接完成。此调用是异步的,需要实现MediaScannerConnectionClient来通知连接何时建立,也可使用该类通知扫描何时完成,完成后可断开媒体扫描器连接。
以下是使用媒体扫描器将新文件添加到媒体库的示例代码:
MediaScannerConnectionClient mediaScannerClient = new
MediaScannerConnectionClient() {
private MediaScannerConnection msc = null;
{
msc = new MediaScannerConnection(getApplicationContext(), this);
msc.connect();
}
public void onMediaScannerConnected() {
msc.scanFile("/sdcard/test1.jpg", null);
}
public void onScanCompleted(String path, Uri uri) {
msc.disconnect();
}
};
- 手动插入媒体 :可创建一个新的ContentValues对象,并将其插入到相应的媒体库内容提供者中,从而将新媒体添加到媒体库。指定的元数据可包括新媒体文件的标题、时间戳和地理编码信息。同时,必须指定要添加的媒体文件的绝对路径。获取应用程序的ContentResolver,并使用它将新行插入媒体库。插入后,应使用广播Intent宣布媒体文件的可用性。
以下是手动插入媒体的示例代码:
ContentValues content = new ContentValues(3);
content.put(Audio.AudioColumns.TITLE, "TheSoundandtheFury");
content.put(Audio.AudioColumns.DATE_ADDED,
System.currentTimeMillis() / 1000);
content.put(Audio.Media.MIME_TYPE, "audio/amr");
content.put(MediaStore.Audio.Media.DATA, "/sdcard/myoutputfile.mp4");
ContentResolver resolver = getContentResolver();
Uri uri = resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
content);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
1.3 原始音频处理
AudioTrack和AudioRecord类可让你直接从设备的音频输入硬件录制音频,并将PCM音频缓冲区直接流式传输到音频硬件进行播放。使用AudioTrack流模式,可近乎实时地处理传入音频并播放,从而在设备上处理传入或传出音频并对原始音频进行信号处理。
1.3.1 使用AudioRecord录制声音
使用AudioRecord类可直接从硬件缓冲区录制音频。创建新的AudioRecord对象时,需指定源、频率、通道配置、音频编码和缓冲区大小。
以下是使用AudioRecord录制原始音频到SD卡文件的示例代码:
int frequency = 11025;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
File file = new File(Environment.getExternalStorageDirectory(), "raw.pcm");
try {
file.createNewFile();
} catch (IOException e) {}
try {
OutputStream os = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
int bufferSize = AudioRecord.getMinBufferSize(frequency,
channelConfiguration,
audioEncoding);
short[] buffer = new short[bufferSize];
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
frequency,
channelConfiguration,
audioEncoding, bufferSize);
audioRecord.startRecording();
while (isRecording) {
int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);
for (int i = 0; i < bufferReadResult; i++)
dos.writeShort(buffer[i]);
}
audioRecord.stop();
dos.close();
} catch (Throwable t) {}
1.3.2 使用AudioTrack播放声音
使用AudioTrack类可将原始音频直接播放到硬件缓冲区。创建新的AudioTrack对象时,需指定流模式、频率、通道配置、音频编码类型和要播放的音频长度。
以下是播放之前录制的原始音频的示例代码:
int frequency = 11025/2;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
File file = new File(Environment.getExternalStorageDirectory(), "raw.pcm");
int audioLength = (int)(file.length()/2);
short[] audio = new short[audioLength];
try {
InputStream is = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(is);
DataInputStream dis = new DataInputStream(bis);
int i = 0;
while (dis.available() > 0) {
audio[audioLength] = dis.readShort();
i++;
}
dis.close();
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
frequency,
channelConfiguration,
audioEncoding,
audioLength,
AudioTrack.MODE_STREAM);
audioTrack.play();
audioTrack.write(audio, 0, audioLength);
} catch (Throwable t) {}
1.4 语音识别
自Android 1.5(API级别3)起,Android使用RecognizerIntent类支持语音输入和语音识别。该API可让你使用标准语音输入对话框接受语音输入。
语音识别通过调用startActivityForResult方法并传入指定RecognizerIntent.ACTION_RECOGNIZE_SPEECH动作常量的Intent来启动。启动Intent必须包含RecognizerIntent.EXTRA_LANGUAGE_MODEL额外参数,以指定用于解析输入音频的语言模型,可选值为LANGUAGE_MODEL_FREE_FORM或LANGUAGE_MODEL_WEB_SEARCH。还可使用一些可选的额外参数来控制语言、潜在结果数量和显示提示。
以下是启动英语语音识别、返回一个结果并使用自定义提示的示例代码:
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
"or forever hold your peace");
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.ENGLISH);
startActivityForResult(intent, VOICE_RECOGNITION);
用户完成语音输入后,语音识别引擎会分析和处理结果,并通过onActivityResult处理程序以字符串数组列表的形式返回结果。
以下是获取语音识别结果的示例代码:
@Override
protected void onActivityResult(int requestCode,
int resultCode,
Intent data) {
if (requestCode == VOICE_VOICE_RECOGNITION && resultCode == RESULT_OK) {
ArrayList<String> results;
results = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
// TODO Do something with the recognized voice strings
}
super.onActivityResult(requestCode, resultCode, data);
}
2. 电话与短信功能
2.1 电话功能
2.1.1 启动拨号器发起电话呼叫
最佳做法是使用Intent启动拨号器应用来发起新的电话呼叫。使用Intent动作启动拨号器活动,并使用tel:方案指定要拨打的号码作为Intent的数据组件。使用Intent.ACTION_DIAL动作启动拨号器,而不是立即拨号,此动作会启动拨号器活动,传入指定号码,但允许拨号器应用管理呼叫初始化。
以下是拨号的基本代码:
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:1234567"));
startActivity(intent);
2.1.2 替换原生拨号器
替换原生拨号器应用包括两个步骤:
1. 拦截当前由原生拨号器处理的Intent。
2. 发起并可选地管理呼出电话。
原生拨号器应用会响应与用户按下硬件呼叫按钮、使用tel:方案查看数据或使用tel:方案请求拨号对应的Intent动作。要拦截这些请求,需在新的Activity中包含
标签,监听以下动作:
- Intent.ACTION_CALL_BUTTON:设备硬件呼叫按钮被按下时广播此动作。
- Intent.ACTION_DIAL:应用想要启动拨号器进行电话呼叫时使用的Intent动作。
- Intent.ACTION_VIEW:应用想要查看数据时使用的动作。
以下是包含Intent过滤器的Activity清单片段示例:
<activity
android:name=".MyDialerActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.CALL_BUTTON" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tel" />
</intent-filter>
</activity>
启动应用后,可让用户输入或修改要拨打的号码并发起呼出电话。最简单的方法是使用现有的电话堆栈,可使用Intent.ACTION_CALL动作发起呼叫,让系统处理拨号、连接和语音处理,但应用必须具有CALL_PHONE权限。也可通过实现自己的拨号和语音处理框架完全替换呼出电话堆栈。
2.1.3 访问电话和网络属性及状态
通过TelephonyManager可访问电话的许多属性,包括设备、网络、SIM和数据状态详细信息。
以下是访问TelephonyManager的代码:
String srvcName = Context.TELEPHONY_SERVICE;
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(srvcName);
读取电话设备详细信息
使用TelephonyManager可获取电话类型(GSM或CDMA)、唯一ID(IMEI或MEID)、软件版本和号码。除电话类型外,读取其他属性需在应用清单中包含READ_PHONE_STATE权限。
以下是读取电话详细信息的代码:
int phoneType = telephonyManager.getPhoneType();
switch (phoneType) {
case (TelephonyManager.PHONE_TYPE_CDMA): break;
case (TelephonyManager.PHONE_TYPE_GSM) : break;
case (TelephonyManager.PHONE_TYPE_NONE): break;
default: break;
}
// -- These require READ_PHONE_STATE uses-permission --
String deviceId = telephonyManager.getDeviceId();
String softwareVersion = telephonyManager.getDeviceSoftwareVersion();
String phoneNumber = telephonyManager.getLine1Number();
读取数据连接和传输状态
使用getDataState和getDataActivity方法可分别获取当前数据连接状态和传输活动。
以下是读取数据连接和传输状态的代码:
int dataActivity = telephonyManager.getDataActivity();
int dataState = telephonyManager.getDataState();
switch (dataActivity) {
case TelephonyManager.DATA_ACTIVITY_IN : break;
case TelephonyManager.DATA_ACTIVITY_OUT : break;
case TelephonyManager.DATA_ACTIVITY_INOUT : break;
case TelephonyManager.DATA_ACTIVITY_NONE : break;
}
switch (dataState) {
case TelephonyManager.DATA_CONNECTED : break;
case TelephonyManager.DATA_CONNECTING : break;
case TelephonyManager.DATA_DISCONNECTED : break;
case TelephonyManager.DATA_SUSPENDED : break;
}
读取网络详细信息
连接到网络时,可使用TelephonyManager读取移动国家和网络代码(MCC+MNC)、国家ISO代码以及连接的网络类型。这些命令仅在连接到移动网络时有效,CDMA网络可能不可靠。
以下是读取网络详细信息的代码:
String networkCountry = telephonyManager.getNetworkCountryIso();
String networkOperatorId = telephonyManager.getNetworkOperator();
String networkName = telephonyManager.getNetworkOperatorName();
int networkType = telephonyManager.getNetworkType();
switch (networkType) {
case (TelephonyManager.NETWORK_TYPE_1xRTT) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_CDMA) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_EDGE) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_EVDO_0) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_EVDO_A) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_GPRS) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_HSDPA) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_HSPA) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_HSUPA) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_UMTS) : [ . . . do something . . . ] break;
case (TelephonyManager.NETWORK_TYPE_UNKNOWN) : [ . . . do something . . . ] break;
default: break;
}
读取SIM详细信息
如果应用在GSM设备上运行,可从TelephonyManager查询SIM详细信息,包括ISO国家代码、运营商名称、运营商MCC和MNC。获取当前SIM的序列号需在应用清单中包含READ_PHONE_STATE权限。在使用这些方法之前,必须确保SIM处于就绪状态。
以下是读取SIM详细信息的代码:
int simState = telephonyManager.getSimState();
switch (simState) {
case (TelephonyManager.SIM_STATE_ABSENT): break;
case (TelephonyManager.SIM_STATE_NETWORK_LOCKED): break;
case (TelephonyManager.SIM_STATE_PIN_REQUIRED): break;
case (TelephonyManager.SIM_STATE_PUK_REQUIRED): break;
case (TelephonyManager.SIM_STATE_UNKNOWN): break;
case (TelephonyManager.SIM_STATE_READY): {
String simCountry = telephonyManager.getSimCountryIso();
String simOperatorCode = telephonyManager.getSimOperator();
String simOperatorName = telephonyManager.getSimOperatorName();
String simSerial = telephonyManager.getSimSerialNumber();
break;
}
default: break;
}
2.1.4 监控电话状态、电话活动和数据连接变化
Android电话API可让你监控电话状态、获取来电号码并观察数据连接、信号强度和网络连接的变化。要监控和管理电话状态,应用必须在清单中指定READ_PHONE_STATE权限。
通过扩展PhoneStateListener类可监听并响应电话状态变化事件,包括呼叫状态、小区位置变化、语音邮件和呼叫转移状态、电话服务变化以及移动信号强度变化。
以下是PhoneStateListener骨架类代码:
PhoneStateListener phoneStateListener = new PhoneStateListener() {
public void onCallForwardingIndicatorChanged(boolean cfi) {}
public void onCallStateChanged(int state, String incomingNumber) {}
public void onCellLocationChanged(CellLocation location) {}
public void onDataActivity(int direction) {}
public void onDataConnectionStateChanged(int state) {}
public void onMessageWaitingIndicatorChanged(boolean mwi) {}
public void onServiceStateChanged(ServiceState serviceState) {}
public void onSignalStrengthChanged(int asu) {}
};
注册PhoneStateListener时,需使用位掩码指定要监听的事件:
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_CELL_LOCATION |
PhoneStateListener.LISTEN_DATA_ACTIVITY |
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
PhoneStateListener.LISTEN_SERVICE_STATE |
PhoneStateListener.LISTEN_SIGNAL_STRENGTH);
取消注册监听器,可调用listen方法并传入PhoneStateListener.LISTEN_NONE作为位字段参数:
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_NONE);
监控来电
监控电话状态的一个常见原因是检测并响应来电。可重写PhoneStateListener实现中的onCallStateChanged方法,并进行注册以接收呼叫状态变化的通知。
以下是监控电话呼叫的代码:
PhoneStateListener callStateListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
// TODO React to incoming call.
}
};
telephonyManager.listen(callStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
onCallStateChanged处理程序接收与来电关联的电话号码,state参数表示当前呼叫状态,有以下三种值:
- TelephonyManager.CALL_STATE_IDLE:电话既不响铃也不在通话中。
- TelephonyManager.CALL_STATE_RINGING:电话正在响铃。
- TelephonyManager.CALL_STATE_OFFHOOK:电话正在通话中。
跟踪小区位置变化
重写PhoneStateListener实现中的onCellLocationChanged方法,可在当前小区位置发生变化时获取通知。注册监听小区位置变化前,需在应用清单中添加ACCESS_COARSE_LOCATION权限。
以下是跟踪小区变化的代码:
PhoneStateListener cellLocationListener = new PhoneStateListener() {
public void onCellLocationChanged(CellLocation location) {
GsmCellLocation gsmLocation = (GsmCellLocation)location;
Toast.makeText(getApplicationContext(),
String.valueOf(gsmLocation.getCid()),
Toast.LENGTH_LONG).show();
}
};
telephonyManager.listen(cellLocationListener,
PhoneStateListener.LISTEN_CELL_LOCATION);
跟踪服务变化
onServiceStateChanged处理程序可跟踪设备小区服务的服务详细信息。使用ServiceState参数可获取当前服务状态的详细信息。
以下是监控服务状态变化的代码:
PhoneStateListener serviceStateListener = new PhoneStateListener() {
public void onServiceStateChanged(ServiceState serviceState) {
if (serviceState.getState() == ServiceState.STATE_IN_SERVICE) {
String toastText = serviceState.getOperatorAlphaLong();
Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_SHORT);
}
}
};
telephonyManager.listen(serviceStateListener,
PhoneStateListener.LISTEN_SERVICE_STATE);
2.2 短信功能
Android提供了完整的短信功能,可在应用中发送和接收短信。可使用Android API创建自己的短信客户端应用,替代软件栈中自带的原生客户端,也可将短信功能集成到自己的应用中,创建使用短信作为传输层的社交应用。
在后续的详细项目中,可使用SMS Manager创建紧急短信响应器,在紧急情况下,用户可快速或自动回复询问其安全状况的人。
2.2.1 使用 Intent 发送短信和彩信
使用 Intent 可以方便地调用系统的短信或彩信发送界面。以下是使用 Intent 发送短信的示例代码:
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:123456789"));
intent.putExtra("sms_body", "这是一条测试短信");
startActivity(intent);
上述代码中,
ACTION_SENDTO
表示发送短信的动作,
smsto:
后面跟上要发送的电话号码,
sms_body
用于设置短信的内容。
若要发送彩信,可使用如下代码:
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/jpeg");
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/image.jpg"));
intent.putExtra("sms_body", "这是一条包含图片的彩信");
startActivity(Intent.createChooser(intent, "选择彩信应用"));
这里,
ACTION_SEND
表示发送内容的动作,
setType
指定要发送的内容类型,
EXTRA_STREAM
用于添加要发送的文件,
sms_body
依然是设置短信内容。
2.2.2 使用 SMS Manager 发送短信
SMS Manager 提供了更灵活的短信发送方式,可直接在应用内发送短信而无需调用系统界面。以下是使用 SMS Manager 发送短信的示例代码:
SmsManager smsManager = SmsManager.getDefault();
String phoneNumber = "123456789";
String message = "这是使用 SMS Manager 发送的短信";
smsManager.sendTextMessage(phoneNumber, null, message, null, null);
代码中,首先通过
getDefault
方法获取 SMS Manager 的实例,然后调用
sendTextMessage
方法发送短信,该方法的参数依次为:目标电话号码、短信中心号码(一般为
null
)、短信内容、发送状态的 PendingIntent(可设为
null
)、送达报告的 PendingIntent(可设为
null
)。
2.2.3 处理 incoming SMS 消息
要处理接收到的短信,需要创建一个广播接收器来监听短信接收的广播。以下是一个简单的示例:
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
String sender = smsMessage.getOriginatingAddress();
String message = smsMessage.getMessageBody();
// 处理接收到的短信
Log.d("SMS", "收到来自 " + sender + " 的短信: " + message);
}
}
}
}
}
在 AndroidManifest.xml 中注册该广播接收器:
<receiver android:name=".SmsReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
同时,需要在 AndroidManifest.xml 中添加接收短信的权限:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
2.2.4 实现紧急短信响应器项目
下面详细介绍如何使用 SMS Manager 创建紧急短信响应器。该响应器在紧急情况下,用户可快速或自动回复询问其安全状况的人。
项目思路
- 监听来电和短信,当收到特定联系人的询问短信时,根据用户设置的紧急状态,自动回复预设的短信。
- 提供一个界面让用户设置紧急状态和回复内容。
代码实现
- 创建紧急状态设置界面 :在布局文件中创建一个简单的界面,包含一个开关用于设置紧急状态,一个输入框用于设置回复内容,一个保存按钮。
<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="16dp">
<Switch
android:id="@+id/emergencySwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="紧急状态" />
<EditText
android:id="@+id/replyEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="设置回复内容" />
<Button
android:id="@+id/saveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="保存设置" />
</LinearLayout>
- 在 Activity 中处理设置逻辑 :
public class EmergencySettingsActivity extends AppCompatActivity {
private Switch emergencySwitch;
private EditText replyEditText;
private Button saveButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_emergency_settings);
emergencySwitch = findViewById(R.id.emergencySwitch);
replyEditText = findViewById(R.id.replyEditText);
saveButton = findViewById(R.id.saveButton);
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean isEmergency = emergencySwitch.isChecked();
String replyMessage = replyEditText.getText().toString();
// 保存设置到 SharedPreferences
SharedPreferences preferences = getSharedPreferences("EmergencySettings", MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isEmergency", isEmergency);
editor.putString("replyMessage", replyMessage);
editor.apply();
Toast.makeText(EmergencySettingsActivity.this, "设置保存成功", Toast.LENGTH_SHORT).show();
}
});
}
}
- 在广播接收器中处理短信回复逻辑 :
public class EmergencySmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
SharedPreferences preferences = context.getSharedPreferences("EmergencySettings", MODE_PRIVATE);
boolean isEmergency = preferences.getBoolean("isEmergency", false);
String replyMessage = preferences.getString("replyMessage", "");
if (isEmergency) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
String sender = smsMessage.getOriginatingAddress();
String message = smsMessage.getMessageBody();
// 假设特定关键词为 "安全状况"
if (message.contains("安全状况")) {
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(sender, null, replyMessage, null, null);
}
}
}
}
}
}
}
- 在 AndroidManifest.xml 中注册广播接收器 :
<receiver android:name=".EmergencySmsReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
总结
通过上述内容,我们详细介绍了 Android 中的多媒体处理和电话短信功能。在多媒体处理方面,涵盖了 EXIF 数据处理、向媒体库添加新媒体、原始音频处理以及语音识别等内容,每个部分都给出了具体的操作步骤和示例代码。在电话短信功能方面,包括了电话的拨号、状态监控、短信和彩信的发送以及短信的接收处理等,同样提供了详细的代码示例和操作说明。掌握这些知识和技能,能够帮助开发者在 Android 应用开发中更好地实现多媒体和通信相关的功能。
流程图
graph LR
A[开始] --> B[多媒体处理]
B --> B1[EXIF数据处理]
B --> B2[添加新媒体到媒体库]
B --> B3[原始音频处理]
B --> B4[语音识别]
A --> C[电话短信功能]
C --> C1[电话功能]
C1 --> C11[启动拨号器]
C1 --> C12[替换原生拨号器]
C1 --> C13[访问电话和网络属性]
C1 --> C14[监控电话状态]
C --> C2[短信功能]
C2 --> C21[使用Intent发送短信彩信]
C2 --> C22[使用SMS Manager发送短信]
C2 --> C23[处理接收到的短信]
C2 --> C24[实现紧急短信响应器]
B1 --> D[结束]
B2 --> D
B3 --> D
B4 --> D
C11 --> D
C12 --> D
C13 --> D
C14 --> D
C21 --> D
C22 --> D
C23 --> D
C24 --> D
表格
| 功能模块 | 具体功能 | 关键类或方法 |
|---|---|---|
| 多媒体处理 | EXIF 数据处理 | ExifInterface 的 getAttribute 和 setAttribute 方法 |
| 多媒体处理 | 添加新媒体到媒体库 | MediaScannerConnection、ContentResolver 的 insert 方法 |
| 多媒体处理 | 原始音频处理 | AudioRecord、AudioTrack |
| 多媒体处理 | 语音识别 | RecognizerIntent |
| 电话短信功能 | 电话拨号 | Intent.ACTION_DIAL、Intent.ACTION_CALL |
| 电话短信功能 | 监控电话状态 | PhoneStateListener |
| 电话短信功能 | 发送短信彩信 | Intent、SmsManager |
| 电话短信功能 | 处理接收到的短信 |
广播接收器监听
android.provider.Telephony.SMS_RECEIVED
广播
|
超级会员免费看
21

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



