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.拦截未接来电通知,不显示在状态栏StatusBarr中

源码位置 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是个好东西,多加日志,多分析,这样很容易上手。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,756评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,699评论 2 59
  • 真正靠谱的人,都有这3种能力 一个人之所以靠谱,往往是因为3种能力: 高效的闭环沟通能力、有坑必填的执行能力、抗打...
    飞轩皓阅读 167评论 0 0
  • 2017-10-16 姓名:李义 公司:慈溪创鑫车辆零部件有限公司 组别:259期利他二组 【知~学习】 背诵 六...
    六度轮回阅读 176评论 0 0
  • 哈喽 我仿佛听到谁在呼唤我 嗯嗯,没错 我就是小群子姐 你们有没有想我? 今天跟大家聊聊【中国式“奢婚”】 不知道...
    三分钟资讯阅读 265评论 0 0