MTK-Android13-Dialer 通话界面定制修改
定制通话界面
文章目录
- 前言-需求
- 一、参考资料
- 二、修改文件-实现方案
- 修改文件
- 修改思路
- 实现方案
- isSupportedButton 方法去掉id 判断
- onViewCreated 方法中去掉需要添加的UI组件
- onInCallScreenDialpadVisibilityChange 方法屏蔽组件BUTTON_DIALPAD
- setHold 方法屏蔽掉需要屏蔽的组件操作BUTTON_HOLD 逻辑
- setAudioState 去除静音和免提相关功能业务
- updateRecordStateUi 去除录音相关业务
- 三、源码分析
- InCallFragment 分析
- ButtonController 源码分析
- 总结
前言-需求
Android中打电话的应用是Dialer,部分商用的场景比如:电话亭、公司共用电话、校园共用电话场景是由一定的定制场景的。
具体需求如下:把通话界面的所有功能按钮全部去掉
一、参考资料
Android8.1 MTK 平台Dialer修改(通话常亮、按钮接听)
Android Dialer源码分析之IncallUI中SpeakerButton点击后显示音频选择器
IncallUI里面各个按键功能流程
Android Dialer源码分析之IncallUI中SpeakerButton点击后显示音频选择器
备注:
- Dialer 源码分析比较少、定制比较少,可以借鉴下 针对自己的需求看看源码
- 参考资料仅给一下思考,还是得根据自己AOSP 源码查看具体代码,根据架构、层次、业务进行修改!
二、修改文件-实现方案
修改文件
vendor/mediatek/proprietary/packages/apps/Dialer/java/com/android/incallui/incall/impl/InCallFragment.java
修改思路
打开通话界面进行电话时候,查看日志如下,找到对应的源码 InCallFragment
实现方案
在InCallFragment
中屏蔽掉动态添加的组件和相关id 获取判断逻辑即可
isSupportedButton 方法去掉id 判断
private static boolean isSupportedButton(@InCallButtonIds int id) {return// id == InCallButtonIds.BUTTON_AUDIO// || id == InCallButtonIds.BUTTON_MUTE// || id == InCallButtonIds.BUTTON_DIALPAD// id == InCallButtonIds.BUTTON_HOLDid == InCallButtonIds.BUTTON_SWAP// || id == InCallButtonIds.BUTTON_UPGRADE_TO_VIDEO// || id == InCallButtonIds.BUTTON_ADD_CALL|| id == InCallButtonIds.BUTTON_MERGE|| id == InCallButtonIds.BUTTON_MANAGE_VOICE_CONFERENCE|| id == InCallButtonIds.BUTTON_SWAP_SIM|| id == InCallButtonIds.BUTTON_UPGRADE_TO_RTT/// M: [Voice Record]// || id == InCallButtonIds.BUTTON_SWITCH_VOICE_RECORD/// M: [Hang Up]|| id == InCallButtonIds.BUTTON_HANG_UP_ALL|| id == InCallButtonIds.BUTTON_HANG_UP_HOLD/// M: [ECT(blind)]|| id == InCallButtonIds.BUTTON_ECT|| id == InCallButtonIds.BUTTON_BLIND_ECT/// M: [One way video]|| id == InCallButtonIds.BUTTON_ONE_WAY_VIDEO/// M: ALPS03949921, add switch_to_secondary to enable and disable.|| id == InCallButtonIds.BUTTON_SWITCH_TO_SECONDARY;}
onViewCreated 方法中去掉需要添加的UI组件
@Overridepublic void onViewCreated(@NonNull View view, @Nullable Bundle bundle) {LogUtil.i("InCallFragment.onViewCreated", null);super.onViewCreated(view, bundle);/// M: [Voice Record] Add for recording. @{initVoiceRecorderIcon(view);/// @}inCallScreenDelegate =FragmentUtils.getParent(this, InCallScreenDelegateFactory.class).newInCallScreenDelegate();Assert.isNotNull(inCallScreenDelegate);// buttonControllers.add(new ButtonController.MuteButtonController(inCallButtonUiDelegate));// buttonControllers.add(new ButtonController.SpeakerButtonController(inCallButtonUiDelegate));// buttonControllers.add(new ButtonController.DialpadButtonController(inCallButtonUiDelegate));// buttonControllers.add(new ButtonController.HoldButtonController(inCallButtonUiDelegate));// buttonControllers.add(new ButtonController.AddCallButtonController(inCallButtonUiDelegate));buttonControllers.add(new ButtonController.SwapButtonController(inCallButtonUiDelegate));buttonControllers.add(new ButtonController.MergeButtonController(inCallButtonUiDelegate));buttonControllers.add(new ButtonController.SwapSimButtonController(inCallButtonUiDelegate));/* buttonControllers.add(new ButtonController.UpgradeToVideoButtonController(inCallButtonUiDelegate));*/buttonControllers.add(new UpgradeToRttButtonController(inCallButtonUiDelegate));buttonControllers.add(new ButtonController.ManageConferenceButtonController(inCallScreenDelegate));buttonControllers.add(new ButtonController.SwitchToSecondaryButtonController(inCallScreenDelegate));/// M: [Voice Record] @{/* buttonControllers.add(new ButtonController.SwitchVoiceRecordButtonController(inCallButtonUiDelegate));*//// @}/// M: [Hang Up] @{buttonControllers.add(new ButtonController.HangupAllButtonController(inCallScreenDelegate));buttonControllers.add(new ButtonController.HangupHoldButtonController(inCallScreenDelegate));/// @}/// M: [ECT(blind)] @{buttonControllers.add(new ButtonController.ECTButtonController(inCallButtonUiDelegate));buttonControllers.add(new ButtonController.BlindECTButtonController(inCallButtonUiDelegate));/// @}/// M: [One way video] @{buttonControllers.add(new ButtonController.UpgradeToOneWayVideoButtonController(inCallButtonUiDelegate));/// @}inCallScreenDelegate.onInCallScreenDelegateInit(this);inCallScreenDelegate.onInCallScreenReady();}
onInCallScreenDialpadVisibilityChange 方法屏蔽组件BUTTON_DIALPAD
@Overridepublic void onInCallScreenDialpadVisibilityChange(boolean isShowing) {LogUtil.i("InCallFragment.onInCallScreenDialpadVisibilityChange", "isShowing: " + isShowing);// Take note that the dialpad button isShowing// getButtonController(InCallButtonIds.BUTTON_DIALPAD).setChecked(isShowing);// This check is needed because there is a race condition where we attempt to update// ButtonGridFragment before it is ready, so we check whether it is ready first and once it is// ready, #onButtonGridCreated will mark the dialpad button as isShowing.if (inCallButtonGridFragment != null) {// Update the Android Button's state to isShowing.inCallButtonGridFragment.onInCallScreenDialpadVisibilityChange(isShowing);}Activity activity = getActivity();Window window = activity.getWindow();window.setNavigationBarColor(activity.getColor(isShowing ? android.R.color.background_dark : android.R.color.transparent));}
setHold 方法屏蔽掉需要屏蔽的组件操作BUTTON_HOLD 逻辑
@Overridepublic void setHold(boolean value) {// getButtonController(InCallButtonIds.BUTTON_HOLD).setChecked(value);}
setAudioState 去除静音和免提相关功能业务
@Overridepublic void setAudioState(CallAudioState audioState) {/// M: do not show bluetooth device information. @{/// Google code: LogUtil.i("InCallFragment.setAudioState", "audioState: " + audioState);LogUtil.i("InCallFragment.setAudioState", "isMuted: " + audioState.isMuted() + ", route: "+ CallAudioState.audioRouteToString(audioState.getRoute()) + ", supportMask: "+ CallAudioState.audioRouteToString(audioState.getSupportedRouteMask()));/// @}/// M: ALPS05941240 AudioRouteSelectorDialogFragment would not dismiss when call/// audio state changed. @{AudioRouteSelectorDialogFragment audioRouteSelectorDialog =(AudioRouteSelectorDialogFragment) this.getChildFragmentManager().findFragmentByTag(TAG_AUDIOROUTE_SELECTOR_FRAGMENT);if (audioRouteSelectorDialog != null) {audioRouteSelectorDialog.dismissAllowingStateLoss();audioRouteSelectorDialog = null;}/// @}/* ((SpeakerButtonController) getButtonController(InCallButtonIds.BUTTON_AUDIO)).setAudioState(audioState);*/// getButtonController(InCallButtonIds.BUTTON_MUTE).setChecked(audioState.isMuted());}
updateRecordStateUi 去除录音相关业务
/*** M: [Voice Record] updateRecordStateUi* @param isRecording*/@Overridepublic void updateRecordStateUi(boolean isRecording) {LogUtil.d("InCallFragment.updateRecordStateUi", "[updateRecordStateUi]... " + isRecording);DialerCall ringCall = CallList.getInstance().getIncomingCall();if (isRecording && (ringCall == null)) {updateVoiceRecordIcon(true);} else {updateVoiceRecordIcon(false);}// getButtonController(InCallButtonIds.BUTTON_SWITCH_VOICE_RECORD).setChecked(isRecording);}
三、源码分析
InCallFragment 分析
看源码 如下:
/** Fragment that shows UI for an ongoing voice call. */
public class InCallFragment extends Fragmentimplements InCallScreen,InCallButtonUi,OnClickListener,AudioRouteSelectorPresenter,OnButtonGridCreatedListener {....}
看类定义,它本质上就是一个通话界面的UI,直接集成了Fragment 组件。所以它就是一个显示UI组件并具备生命周期
ButtonController 源码分析
看类定义,原来它就是一个接口,管理Button用的。
/** Manages a single button. */
interface ButtonController {
............
}
那为什么会分析到这里,一方面它从直观上来看,就是管理Button的,再具体看看源码:
- 定义了所有的功能Button
- 对每个自定义功能
Button
描述和定义,都有相关的String/Id
所以,当我们找到这里时候就提供了解决需求的思路,一步一步去解决实际需求和阅读相关源码。
总结
- 这个需求其实很简单的,通过阅读源码并分析源码能够快速实现需求
- 这里面比较坑的是,其实部分按钮咋一看和实际ID 很难对上,本身也不熟悉情况下导致修改错误,建议一个一个或者再无编译报错情况下一个一个验证。
- 初识Dialer 界面源码和部分业务逻辑,实际项目中其实还涉及到在原生APP基础上定制这个UI界面,这样就需要了解这个源码并针对性修改了。