OS: Android 8.1

需求分析

1、禁止系统来电铃声,提供接口给客户自己播放铃声

2、禁止系统拉起来去电页面(InCallActivity),消息通知客户拉起自己的来去电页面

3、禁止来电消息 Notification 显示(包括未接来电),点击跳转至 InCallActivity(未接来电消息可通知客户或者将 PendingIntent 改成客户的)

上代码

1、系统来电铃声播放在 Telecomm 应用中,我们发现一般都是先听到铃声才看到 UI 被拉起,那是因为铃声在 Telecomm 中,UI 需要通过 InCallService 通知到 Dialer 中。

vendor\mediatek\proprietary\packages\services\Telecomm\src\com\android\server\telecom\Ringer.java

  1. public boolean startRinging(Call foregroundCall, boolean isHfpDeviceAttached) {
  2. //cczhegn add return for customer self control ringing, system ignore
  3. if (true) {
  4. return ;
  5. }
  6. if (foregroundCall == null) {
  7. /// M: ALPS03787956 Fix wtf log warning. @{
  8. /// Hand up the call immediately when ringing. Then the foreground call will
  9. /// change to null, but call audio is start ringing at the same time.
  10. /// Log.wtf will occur in this case.
  11. /// Solution:
  12. /// Call audio can handle this case, so change Log.wtf to Log.i here.
  13. Log.i(this, "startRinging called with null foreground call.");
  14. /// @}
  15. return false;
  16. }
  17. AudioManager audioManager =
  18. (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
  19. boolean isVolumeOverZero = audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0;
  20. boolean shouldRingForContact = shouldRingForContact(foregroundCall.getContactUri());
  21. boolean isRingtonePresent = !(mRingtoneFactory.getRingtone(foregroundCall) == null);
  22. boolean isSelfManaged = foregroundCall.isSelfManaged();
  23. ....
  24. }
  25. public void stopRinging() {
  26. //cczheng add return for customer self control ringing, system ignore
  27. if (true) {
  28. return ;
  29. }
  30. if (mRingingCall != null) {
  31. Log.addEvent(mRingingCall, LogUtils.Events.STOP_RINGER);
  32. mRingingCall = null;
  33. }
  34. if (mIsVibrating) {
  35. Log.addEvent(mVibratingCall, LogUtils.Events.STOP_VIBRATOR);
  36. mVibrator.cancel();
  37. mIsVibrating = false;
  38. mVibratingCall = null;
  39. }
  40. }

只需要将 startRinging() 和 stopRinging() 直接 return 即可,系统就不会响铃了。

2、提供播放铃声工具类 RingUtil 给客户

  1. public class RingUtil {
  2. private static final String TAG = "RingUtil";
  3. private static Ringtone ringtone;
  4. private static Ringtone getRing(Context context){
  5. if (null == ringtone){
  6. Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE);
  7. ringtone = RingtoneManager.getRingtone(context, defaultRingtoneUri);
  8. }
  9. return ringtone;
  10. }
  11. public static void startRing(Context context){
  12. getRing(context);
  13. if (!ringtone.isPlaying()){
  14. ringtone.play();
  15. }
  16. }
  17. public static void stopRing(Context context){
  18. getRing(context);
  19. if (ringtone.isPlaying()){
  20. ringtone.stop();
  21. }
  22. }
  23. }

3、禁止系统拉起来去电页面

刚刚上面说到 Telecom 和 Dialer 主要通过 InCallService 通信,重要的两个方法 onCallAdded、onCallRemoved,从字面意思很容易理解,当 call 加入和移除时回调。

InCallPresenter 可以说是 Call 的管理中心,来电去电都经过这处理,所以我们在此处修改比较容易

vendor\mediatek\proprietary\packages\apps\Dialer\java\com\android\incallui\InCallPresenter.java

  1. //来电拉起 InCallActivity 的地方
  2. public void showInCall(boolean showDialpad, boolean newOutgoingCall) {
  3. LogUtil.d("InCallPresenter.showInCall", "Showing InCallActivity");
  4. //cczheng annotaion don't show sysytem InCallActivity
  5. //mContext.startActivity(
  6. //InCallActivity.getIntent(
  7. //mContext, showDialpad, newOutgoingCall, false /* forFullScreen */));
  8. }
  9. //去电拉起 InCallActivity 的地方
  10. public void maybeStartRevealAnimation(Intent intent) {
  11. LogUtil.e("InCallPresenter.OutgoingCall", "maybeStartRevealAnimation");
  12. if (intent == null || mInCallActivity != null) {
  13. return;
  14. }
  15. final Bundle extras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
  16. if (extras == null) {
  17. // Incoming call, just show the in-call UI directly.
  18. return;
  19. }
  20. if (extras.containsKey(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS)) {
  21. // Account selection dialog will show up so don't show the animation.
  22. return;
  23. }
  24. final PhoneAccountHandle accountHandle =
  25. intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
  26. final Point touchPoint = extras.getParcelable(TouchPointManager.TOUCH_POINT);
  27. InCallPresenter.getInstance().setBoundAndWaitingForOutgoingCall(true, accountHandle);
  28. //cczheng annotaion don't show sysytem InCallActivity
  29. LogUtil.e("InCallPresenter.OutgoingCall", "OutgoingCall is preper start inCallActivity.");
  30. //final Intent activityIntent =
  31. //InCallActivity.getIntent(mContext, false, true, false /* forFullScreen */);
  32. //activityIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint);
  33. //mContext.startActivity(activityIntent);
  34. }

4、消息通知客户来去电消息

为了简单我们采用广播的方式,由于 8.1 中静态注册广播有限制,为了突破限制,我们需要在发送广播时加上 intent.addFlags(0x01000000);

vendor\mediatek\proprietary\packages\apps\Dialer\java\com\android\incallui\InCallPresenter.java

  1. String number;
  2. public void onCallAdded(final android.telecom.Call call) {
  3. LatencyReport latencyReport = new LatencyReport(call);
  4. if (shouldAttemptBlocking(call)) {
  5. maybeBlockCall(call, latencyReport);
  6. } else {
  7. if (call.getDetails().hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL)) {
  8. mExternalCallList.onCallAdded(call);
  9. } else {
  10. latencyReport.onCallBlockingDone();
  11. mCallList.onCallAdded(mContext, call, latencyReport);
  12. }
  13. }
  14. // Since a call has been added we are no longer waiting for Telecom to send us a call.
  15. setBoundAndWaitingForOutgoingCall(false, null);
  16. call.registerCallback(mCallCallback);
  17. //cczheng add when incall or outcall added notify user can start there incallui
  18. number = TelecomCallUtil.getNumber(call);
  19. if (isOutGoingCall) {
  20. LogUtil.e("InCallPresenter.OutgoingCall", "OutgoingCall number=="+number);
  21. Intent intent = new Intent("com.android.outgoingcall.wireless");
  22. intent.putExtra("outgoingNumber", number);
  23. intent.addFlags(0x01000000);
  24. mContext.sendBroadcast(intent);
  25. }else{
  26. LogUtil.i("InCallPresenter.IncomingCall", "IncomingCall number=="+number);
  27. Intent intentcc = new Intent("com.android.incomingcall.wireless");
  28. intentcc.putExtra("incomingNumber", number);
  29. intentcc.addFlags(0x01000000);
  30. mContext.sendBroadcast(intentcc);
  31. }
  32. }

在 onCallAdded() 方法中,可以看到我们添加了 isOutGoingCall 变量判读是来电还是去电,分别对应不用的 action,通过 TelecomCallUtil 获取当前 call 的 number 顺带发送

5、来去电类型 isOutGoingCall 区分

回到刚刚的屏蔽去电拉起页面的方法 maybeStartRevealAnimation() 中,其中有获取 EXTRA_OUTGOING_CALL_EXTRAS 参数,经过验证确实来电不带此参数,去电带参数

vendor\mediatek\proprietary\packages\apps\Dialer\java\com\android\incallui\InCallPresenter.java

  1. //cczheng add for distinguish incall or outgogingcall
  2. private boolean isOutGoingCall;
  3. public void maybeStartRevealAnimation(Intent intent) {
  4. LogUtil.e("InCallPresenter.OutgoingCall", "maybeStartRevealAnimation");
  5. if (intent == null || mInCallActivity != null) {
  6. return;
  7. }
  8. final Bundle extras = intent.getBundleExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS);
  9. if (extras == null) {
  10. // Incoming call, just show the in-call UI directly.
  11. isOutGoingCall = false;//cczheng add for incomingcall
  12. return;
  13. }
  14. if (extras.containsKey(android.telecom.Call.AVAILABLE_PHONE_ACCOUNTS)) {
  15. // Account selection dialog will show up so don't show the animation.
  16. return;
  17. }
  18. final PhoneAccountHandle accountHandle =
  19. intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
  20. final Point touchPoint = extras.getParcelable(TouchPointManager.TOUCH_POINT);
  21. InCallPresenter.getInstance().setBoundAndWaitingForOutgoingCall(true, accountHandle);
  22. LogUtil.e("InCallPresenter.OutgoingCall", "OutgoingCall is preper start inCallActivity.");
  23. isOutGoingCall = true;//cczhegn add for outgongcall
  24. //final Intent activityIntent =
  25. //InCallActivity.getIntent(mContext, false, true, false /* forFullScreen */);
  26. //activityIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint);
  27. //mContext.startActivity(activityIntent);
  28. }

6、禁止来电消息 Notification 显示

vendor\mediatek\proprietary\packages\apps\Dialer\java\com\android\incallui\StatusBarNotifier.java

  1. @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
  2. public void updateNotification(CallList callList) {
  3. ///cczheng annotaion for don't show incallnotification when pstnoverlayactivity in font
  4. //updateInCallNotification(callList);
  5. }

直接注释 updateInCallNotification()

7、未接来电消息处理

回到 Telecomm 中,MissedCallNotifierImpl 负责管理未接来电消息,如果将 android 自己的 Notification 屏蔽,通知客户自己去显示,略微麻烦,用户需要自己建数据库保存通知已读未读状态,

因为重启需要查询判断是否需要再次显示。这样你可以在 showMissedCallNotification() 中直接发送通知后 return。我们此处采用第二种方式,修改系统 Notification 的 PendingIntent 为客户

vendor\mediatek\proprietary\packages\services\Telecomm\src\com\android\server\telecom\ui\MissedCallNotifierImpl.java

  1. private PendingIntent createCallLogPendingIntent(UserHandle userHandle) {
  2. //cczheng add for jump to customer app
  3. try {
  4. Intent intentc = mContext.getPackageManager().getLaunchIntentForPackage("your customer app packageName");
  5. return PendingIntent.getActivity(mContext, 11, intentc, 0);
  6. }catch (Exception e){
  7. e.printStackTrace();
  8. Intent intent = new Intent(Intent.ACTION_VIEW, null);
  9. intent.setType(Calls.CONTENT_TYPE);
  10. TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(mContext);
  11. taskStackBuilder.addNextIntent(intent);
  12. return taskStackBuilder.getPendingIntent(0, 0, null, userHandle);
  13. }
  14. }

8、按下音量键和电源键静音

系统播放来电铃声时,此时按下音量键或电源键,默认都会停止播放铃声。但这是系统播放铃声的情况下,现在我们已经开发给

客户自己去播放铃声了,所以原来的逻辑就会失效,只能客户自己去停止铃声,但是来电页面响铃中,客户是监听不到音量键或

电源键事件的,只能在系统通知了。

vendor\mediatek\proprietary\packages\services\Telecomm\src\com\android\server\telecom\TelecomServiceImpl.java

  1. @Override
  2. public void silenceRinger(String callingPackage) {
  3. try {
  4. Log.startSession("TSI.sR");
  5. synchronized (mLock) {
  6. enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
  7. long token = Binder.clearCallingIdentity();
  8. try {
  9. Log.i(this, "Silence Ringer requested by %s", callingPackage);
  10. //cczheng add for notify custmer press valume/power need silence ringer
  11. mContext.sendBroadcast(new Intent("com.android.key.silence.ringer"));
  12. mCallsManager.getCallAudioManager().silenceRingers();
  13. mCallsManager.getInCallController().silenceRinger();
  14. } finally {
  15. Binder.restoreCallingIdentity(token);
  16. }
  17. }
  18. } finally {
  19. Log.endSession();
  20. }
  21. }

Android MTK平台 客制化系统来电界面(屏蔽 InCallUI 提供接口给客户自行展示来电去电页面)的更多相关文章

  1. MTK Android [输入法]客制化系统默认输入法-搜狗输入法

    1.frameworks/base/packages/SettingsProvider/res/values/defaults.xml <!--Sogou input method is use ...

  2. Android MTK6580 客制化关机充电动画

    1.客制化关机充电图片 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/xxx 找到对应分辨率替换 2.调整显示图片位置.大小 ...

  3. Dynamics AX 2012 R2 客制化RDP报表参数对话框

    当我们在使用RDP报表时,AX会根据Data Contract,自动生成报表参数对话框上的字段控件.一般情况下,该对话框能够满足我们的需求,但是如果有较为复杂或特殊的需求,就要我们对该对话框进行客制化 ...

  4. BEvent_客制化BusinessEvent通过PLSQL Procedurer接受消息传递(案例)

    2014-06-27 Created By BaoXinjian

  5. Form_通过Zoom客制化跳转页面功能(案例)

    2012-09-08 Created By BaoXinjian

  6. 转:FORM:客制化Form的菜单栏和右鍵菜單

    Oracle EBS还允许客制化Form的菜单栏. 用户最多可以定义45个form-level的trigger,名称必须为SPECIALn, 其中SPECIAL1 to SPECIAL15属于Tool ...

  7. Android RRO机制的运用-----google开机向导客制化

    上周五的时候领导分了一个任务,客户让在google开机向导里面增加一页,首先就想到了android的Overlay,然后网上搜了下,发下有很多人写了这方面的技术.而且写的都还不错,所以本篇只当记录作用 ...

  8. Android MTK平台最完备的开机动画修改教程

    修改手机的开机动画不是什么难事儿. 但修改一款很冷门的"山寨机",就不太好修改第一屏了. 手机是MTK的一款手机,虽然比较贵(价格超过三星Note3),但在我看来跟山寨机木有啥区别 ...

  9. Report_客制化以PLSQL输出XLS标记实现Excel报表(案例)

    2015-02-12 Created By BaoXinjian

随机推荐

  1. Scala 面向对象(七):静态属性和静态方法

    1 Scala中静态的概念-伴生对象 Scala语言是完全面向对象(万物皆对象)的语言,所以并没有静态的操作(即在Scala中没有静态的概念). 但是为了能够和Java语言交互(因为Java中有静态概 ...

  2. Chrome浏览器获取XPATH的方法----通过开发者工具获取

    chrome有自己的开发者工具,可以用这儿来直接获取xpath,都不用担心正确性了. 具体使用步骤如下: 1.在chrome浏览器的右上角有个选择菜单,也就是这个,点一下: 2.在列表最后面有个“更多 ...

  3. mysql常见数据类型

    #常见的数据类型 /* 数值型: 整型 小数: 定点数 浮点数 字符型: 较短的文本:char.varchar 较长的文本:text.blob(较长的二进制数据) 日期型: */ #一.整型 /* 分 ...

  4. opencv毛孔识别(python实现)

    毛孔识别 本文仅仅描述如何用opencv完成一个入门级别的毛孔识别,基于python3.7和 opencv 4.3 原图以及识别生成的效果图 一.首先引入需要的包,然后读取需要识别的图片 import ...

  5. Inoreader - 在线Rss阅读器

  6. 利用华为eNSP模拟器实现vlan之间的通信

    eNSP交换机配置VLAN 1. 搭建网络拓扑结构 运行eNSP>新建拓扑>搭建如下图的拓扑结构>启动设备.利用调色板将划分的vlan进行区分. 2. pc机IP地址配置 pc1的I ...

  7. 性能测试必备知识(5)- 深入理解“CPU 上下文切换”

    做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 前言 上一篇文章中,举例了大量进程等待 CP ...

  8. java计算下一个整5分钟时间点

    需求背景 我的需求是获取当前时间之后的下一个"整5分钟时间点". 首先,那么何为"整5分钟时间点"? 满足以下两个条件的时间: 分钟数等于以下时间中的一个,且秒 ...

  9. Huffuman树--------找最值学会用sort和cmp

    问题描述 Huffman树在编码中有着广泛的应用.在这里,我们只关心Huffman树的构造过程. 给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下: 1. ...

  10. vue学习(十) v-for循环普通数组 、对象数组、 迭代数字

    //html <div id="app"> <p v-for="item in list">{{item}}</p> < ...