应用中有时候会需要获取未接来电,但是当你看完这些未接来电你可能想清除未接来电的通知,及把未接来电变成已读,这时候你需要对数据库操作。
有两种方法可以达到上述需求(其实原理都一样):
一、 直接更改数据库
我们可以参考源码来进行操作,找到MissedCallNotifierImpl.java类,路径是:
packages\services\Telecomm\src\com\android\server\telecom\ui\MissedCallNotifierImpl.java
其中清除未接来电通知的及将未接来电改成已读的代码是:
/** Clears missed call notification and marks the call log's missed calls as read. */
@Override
public void clearMissedCalls() {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
// Clear the list of new missed calls from the call log.
ContentValues values = new ContentValues();
values.put(Calls.NEW, 0);
values.put(Calls.IS_READ, 1);
StringBuilder where = new StringBuilder();
where.append(Calls.NEW);
where.append(" = 1 AND ");
where.append(Calls.TYPE);
where.append(" = ?");
try {
mContext.getContentResolver().update(Calls.CONTENT_URI, values,
where.toString(), new String[]{ Integer.toString(Calls.
MISSED_TYPE) });
} catch (IllegalArgumentException e) {
Log.w(this, "ContactsProvider update command failed", e);
}
}
});
cancelMissedCallNotification();
}
由上面的代码可知这是通过Calls.CONTENT_URI这个URI()来对数据进行操作,将所有的未接的Calls.NEW更新为0,并且将Calls.IS_READ更新为1,这样数据里面的未接来接来电就全部更新为已接了。但进行这些,还不完美,我们还没有清除未接来电的通知,这不,最后cancelMissedCallNotification()就是用来清除通知的。照例,我们也来看看cancelMissedCallNotification()的实现方式:
/** Cancels the "missed call" notification. */
private void cancelMissedCallNotification() {
// Reset the number of missed calls to 0.
mMissedCallCount = 0;
long token = Binder.clearCallingIdentity();
try {
mNotificationManager.cancelAsUser(null, MISSED_CALL_NOTIFICATION_ID,
UserHandle.CURRENT);
} finally {
Binder.restoreCallingIdentity(token);
}
}
这代码任务也很简单,就是清除通知,但是问题来了,我们怎么才能清除另一个应用发出的通知的呢?比如dailer发出未接来电通知,无疑是不能直接清除清除的,只能采取迂回的方法,比如反射调用cancelMissedCallNotification()这个方法,我没有试过,但是应该是可行的!看到你是不是想说,坑爹的Android,不会这么麻烦的吧,清除未接来电都要费这么大的功夫!别着急,接下来揭秘第二种方法,之所以放在后面是因为第二种方法太简单了,以至于你要是先看第二种就不会看第一种方法了。
二、使用系统广播
Android当然不会让你费这么大劲的,早就有广播供开发者使用了,在
packages\services\Telecomm\src\com\android\server\telecom\TelecomBroadcastIntentProcessor.java中可以看到ACTION_CLEAR_MISSED_CALLS这个action,同时你还能看到其他功能的action。
比如:
/** The action used to send SMS response for the missed call notification. */
public static final String ACTION_SEND_SMS_FROM_NOTIFICATION =
"com.android.server.telecom.ACTION_SEND_SMS_FROM_NOTIFICATION";
/** The action used to call a handle back for the missed call notification. */
public static final String ACTION_CALL_BACK_FROM_NOTIFICATION =
"com.android.server.telecom.ACTION_CALL_BACK_FROM_NOTIFICATION";
/** The action used to clear missed calls. */
public static final String ACTION_CLEAR_MISSED_CALLS =
"com.android.server.telecom.ACTION_CLEAR_MISSED_CALLS";
public static final String ACTION_CALL_PULL =
"org.codeaurora.ims.ACTION_CALL_PULL";
也就是说你只要在代码里面如下代码就行了:
- 注:M版本可以这么用,N版本的话sendBroadcast时,除了传送intent过去,还要传一个UserHandler参数!
Intent intent = new Intent();
intent.setAction(ACTION_CLEAR_MISSED_CALLS);
mContext.sendBroadcast(intent);
callInfos.clear();
mHandler.sendEmptyMessage(0x00);
1. **用法是很简单,我们照例追踪一下源码,首先是BroadcastReceiver收到广播**
packages\services\Telecomm\src\com\android\server\telecom\components\TelecomBroadcastReceiver.java
public final class TelecomBroadcastReceiver
extends BroadcastReceiver implements TelecomSystem.Component {
/** {@inheritDoc} */
@Override
public void onReceive(Context context, Intent intent) {
synchronized (getTelecomSystem().getLock()) {
getTelecomSystem().getTelecomBroadcastIntentProcessor().processIntent(intent);
}
}
@Override
public TelecomSystem getTelecomSystem() {
return TelecomSystem.getInstance();
}
}
2. **接着处理广播**
packages\services\Telecomm\src\com\android\server\telecom\TelecomBroadcastIntentProcessor.java
public void processIntent(Intent intent) {
String action = intent.getAction();
Log.v(this, "Action received: %s.", action);
MissedCallNotifier missedCallNotifier = mCallsManager.getMissedCallNotifier();
// Send an SMS from the missed call notification.
if (ACTION_SEND_SMS_FROM_NOTIFICATION.equals(action)) {
// Close the notification shade and the notification itself.
closeSystemDialogs(mContext);
missedCallNotifier.clearMissedCalls();
Intent callIntent = new Intent(Intent.ACTION_SENDTO, intent.getData());
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(callIntent, UserHandle.CURRENT);
// Call back recent caller from the missed call notification.
} else if (ACTION_CALL_BACK_FROM_NOTIFICATION.equals(action)) {
// Close the notification shade and the notification itself.
closeSystemDialogs(mContext);
missedCallNotifier.clearMissedCalls();
Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
callIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
mContext.startActivityAsUser(callIntent, UserHandle.CURRENT);
// Clear the missed call notification and call log entries.
} else if (ACTION_CLEAR_MISSED_CALLS.equals(action)) {
missedCallNotifier.clearMissedCalls();
} else if (ACTION_CALL_PULL.equals(action)) {
// Close the notification shade and the notification itself.
closeSystemDialogs(mContext);
String dialogId = intent.getStringExtra("org.codeaurora.ims.VICE_CLEAR");
int callType = intent.getIntExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, 0);
Log.i(this,"ACTION_CALL_PULL: calltype = " + callType + ", dialogId = " + dialogId);
Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
callIntent.putExtra(TelephonyProperties.EXTRA_IS_CALL_PULL, true);
callIntent.putExtra(TelephonyProperties.EXTRA_SKIP_SCHEMA_PARSING, true);
callIntent.putExtra(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, callType);
callIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
mContext.startActivityAsUser(callIntent, UserHandle.CURRENT);
}
}