Android6.0 原始碼修改之遮蔽系統簡訊功能和來電功能
一、遮蔽系統簡訊功能
1、遮蔽所有簡訊
android 4.2 簡訊傳送流程分析可參考這篇 戳這
原始碼位置 vendor\mediatek\proprietary\packages\apps\Mms\src\com\android\mms\transaction\SmsReceiverService.java
private void handleSmsReceived(Intent intent, int error) { //2018-10-09 cczheng add for intercept mms notifications start if (true) { Log.i("SmsReceived", "handleSmsReceived"); return; } //2018-10-09 cczheng add for intercept mms notifications end SmsMessage[] msgs = Intents.getMessagesFromIntent(intent); /// M:Code analyze 022, check null @{ if (msgs == null) { MmsLog.e(MmsApp.TXN_TAG, "getMessagesFromIntent return null."); return; } MmsLog.d(MmsApp.TXN_TAG, "handleSmsReceived SmsReceiverService"); /// ...... }
在handleSmsReceived()方法中直接return即可,不去解析和分發簡訊訊息,同時這樣操作 簡訊將不會記錄到簡訊資料庫中,插入簡訊訊息到資料庫的方法見下文insertMessage()方法。
2、遮蔽特定的簡訊(特定的簡訊號碼或者簡訊內容)
原始碼位置同上
-
SmsMessage.getOriginatingAddress() 獲取簡訊號碼
-
SmsMessage.getMessageBody() 獲取簡訊內容
private void handleSmsReceived(Intent intent, int error) { SmsMessage[] msgs = Intents.getMessagesFromIntent(intent); ..... /// M:Code analyze 024, print log @{ SmsMessage tmpsms = msgs[0]; MmsLog.d(MmsApp.TXN_TAG, "handleSmsReceived" + (tmpsms.isReplace() ? "(replace)" : "") + " messageUri: " + messageUri + ", address: " + tmpsms.getOriginatingAddress() + ", body: " + tmpsms.getMessageBody()); /// @ //2018-10-09 cczheng add for intercept mms notifications start if ("10010".equals(tmpsms.getOriginatingAddress()) || "話費".contains(tmpsms.getMessageBody())) { Log.i("SmsReceived", "handleSmsReceived"); return; } //2018-10-09 cczheng add for intercept mms notifications end .... }
是否插入簡訊訊息到資料庫,insertMessage()方法在handleSmsReceived()中呼叫
private Uri insertMessage(Context context, SmsMessage[] msgs, int error, String format) { // Build the helper classes to parse the messages. if (msgs == null) { MmsLog.e(MmsApp.TXN_TAG, "insertMessage:getMessagesFromIntent return null."); return null; } /// @} SmsMessage sms = msgs[0]; if (sms.getMessageClass() == SmsMessage.MessageClass.CLASS_0) { MmsLog.d(MmsApp.TXN_TAG, "insertMessage: display class 0 message!"); displayClassZeroMessage(context, msgs, format); return null; } else if (sms.isReplace()) { MmsLog.d(MmsApp.TXN_TAG, "insertMessage: is replace message!"); return replaceMessage(context, msgs, error); } else { MmsLog.d(MmsApp.TXN_TAG, "insertMessage: stored directly!"); return storeMessage(context, msgs, error); } }
3、應用層攔截簡訊(不用修改android原始碼,原理就是用你的app去替代系統預設的簡訊app,過程略繁瑣)
需要新增SmsReceiver,MmsReceiver,ComposeSmsActivity,HeadlessSmsSendService這幾個類,並在AndroidManifest中進行相應配置,具體流程可參考這篇 戳這
二、遮蔽系統來電響鈴和通知提示
遮蔽系統來電可分為三個步驟
1.來電靜音,不響鈴
2.來電結束通話,不出現IncallActivity
3、攔截未接來電通知,不顯示在狀態列StatusBar中
ps:此種修改方式的弊端在於來電時網路資料會離線2s左右
好,現在我們開始按這三個步驟來修改原始碼
1.來電靜音,不響鈴
原始碼位置 packages/services/Telecomm/src/com/android/server/telecom/Ringer.java
private void updateRinging(Call call) {
if (mRingingCalls.isEmpty()) {
stopRinging(call, "No more ringing calls found");
stopCallWaiting(call);
} else {
//2018-10-10 cczheng add anotation function startRingingOrCallWaiting() for silent call start
Log.d("callRinging", "silent call, will not play ringtone");
// startRingingOrCallWaiting(call);
//2018-10-10 cczheng add anotation function startRingingOrCallWaiting() for silent call end
}
}
是的,註釋掉startRingingOrCallWaiting(call);方法就ok啦
2.來電結束通話,不出現IncallActivity
思路:監聽PhoneState,當監聽到響鈴時,直接通過反射呼叫endcall方法結束通話電話。監聽PhoneStateListener可以寫到廣播中,當收到開機廣播時,開始監聽phoneState,這樣和系統保持同步。以下是參考程式碼
public class PhoneStartReceiver extends BroadcastReceiver {
private static final String TAG = "PhoneStartReceiver";
private PhoneCallListener mPhoneCallListener;
private TelephonyManager mTelephonyManager;
@Override
public void onReceive(final Context context, final Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
// endCall when CALL_STATE_RINGING
initPhoneCallListener(context);
}
}
private void initPhoneCallListener(Context context){
mPhoneCallListener = new PhoneCallListener();
mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
mTelephonyManager.listen(mPhoneCallListener, PhoneCallListener.LISTEN_CALL_STATE);
}
public class PhoneCallListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.v(TAG, "onCallStateChanged-state: " + state);
Log.v(TAG, "onCallStateChanged-incomingNumber: " + incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
endCall();
break;
default:
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
private void endCall() {
try {
Method m1 = mTelephonyManager.getClass().getDeclaredMethod("getITelephony");
if (m1 != null) {
m1.setAccessible(true);
Object iTelephony = m1.invoke(mTelephonyManager);
if (iTelephony != null) {
Method m2 = iTelephony.getClass().getDeclaredMethod("silenceRinger");
if (m2 != null) {
m2.invoke(iTelephony);
Log.v(TAG, "silenceRinger......");
}
Method m3 = iTelephony.getClass().getDeclaredMethod("endCall");
if (m3 != null) {
m3.invoke(iTelephony);
Log.v(TAG, "endCall......");
}
}
}
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "endCallError", e);
}
}
}
3.攔截未接來電通知,不顯示在狀態列StatusBar中
原始碼位置 packages/apps/InCallUI/src/com/android/incallui/StatusBarNotifier.java
private void updateInCallNotification(final InCallState state, CallList callList) {
...
final Call call = getCallToShow(callList);
//2018-10-10 cczheng add intercept incoming notification start
if (true) {
if (call != null) {
Log.v("InCallNotification", "phoneNumber = " + call.getNumber());
}
return;
}
//2018-10-10 cczheng add intercept incoming notification end
if (call != null) {
showNotification(call);
} else {
cancelNotification();
}
...
}
其實核心方法就是showNotification(call),傳送通知當statusBar收到通知就處理並顯示在狀態列。
當你發現這樣處理完後,重新mm,然後push替換Dialer.apk重啟後,你會坑爹的發現狀態列那個未接來電圖示依舊顯示,無fa可說,繼續跟蹤日誌揪出罪魁禍首,最終發現另一處奇葩的地方。
原始碼位置 packages/services/Telecomm/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
諾,就是這了,看註釋就明白了吧 Create a system notification for the missed call
/**
* Create a system notification for the missed call.
*
* @param call The missed call.
*/
@Override
public void showMissedCallNotification(Call call) {
////2018-10-10 cczheng hide missed call notification [S]
if (true) {
android.util.Log.i("misscall", "showMissedCallNotification......");
return;
}
///2018-10-10 cczheng hide missed call notification [E]
mMissedCallCount++;
final int titleResId;
final String expandedText; // The text in the notification's line 1 and 2.
....
}
ok,這樣我們就搞定了來電功能。
三、隱藏簡訊應用和電話應用在launcher中顯示(去除AndroidManifest中的category)
<category android:name="android.intent.category.LAUNCHER" />
四、總結
Android原始碼修改沒有大家想象的那麼難,畢竟Google工程師都已經給我們標註了詳細的註釋說明,只是框架和封裝的思路難以理解,這就考驗我們的耐心了,Log是個好東西,多加日誌,多分析,這樣很容易上手。