本流程图基于MTK平台 Android 7.0,普通来电,本流程只作为沟通学习使用

通过前面 Android 7.0 Phone_MT来电流程 的流程分析中我们可以发现,最后是将来电的信息和状态传送到了 dialer 的 incallUI 里面,在 PhoneStatusBar.java 的addNotification方法中通过判断 isHeadsUped 的值来确定是显示 HeadsUp 还是全屏的AnswerFragment ,这里我们重点介绍一下 AnswerFragment 的相关知识。

相关类图

说明:

  • AnswerFragment是一个基类,它只提供了公共的接口和一些方法,没有界面显示
  • GlowPadAnswerFragment和AccessibleAnswerFragment是它的子类,里面包含具体的界面显示和部分逻辑
  • GlowPadAnswerFragment是我们通常意义上看到的AnswerFragment(GlowPadView)
  • AccessibleAnswerFragment当我们打开了Accessibility里面的TalkBack Services后会启用这个界面
  • AnswerFragment界面是CallCardFragment界面的一部分
  • InCallPresenter实例化了InCallActivity和AnswerPresenter,它们两个一起控制着AnswerFragment的显示和隐藏

GlowPadAnswerFragment

类图说明

说明:

  • GlowPadAnswerFragment 加载了 answer_fragment 这个布局
  • answer_fragment 里面只定义了一个自定义view, GlowPadWrapper
  • GlowPadWrapper 继承自 GlowPadView
  • GlowPadView 继承自 View

首先看看启动流程图

再看看界面

说明

  • 红色方框中的界面就是我们的GlowPadAnswerFragment
  • 这里显示了三种状态下的界面,1.未触摸中心点的phone图标、2.触摸了并向右移动到接听图标、3.触摸了但没有移动

通过上面类图的介绍,我们可以知道这个界面最终是由 GlowPadView 这个自定义view显示的,下面我们就来大致了解一下上面类图中各个类的内容和作用:

GlowPadAnswerFragment

这个类的代码量很少,主要就是加载 answer_fragment 布局,并通过 onShowAnswerUi 动态控制动画的开始和停止,通过 showTargets 方法动态调整整个 GlowPadView 的资源文件,包括:显示几个图标,图标的描述字符串的改变,几个图标的改变。

    @Overridepublic void onShowAnswerUi(boolean shown) {Log.d(this, "Show answer UI: " + shown);if (shown) {mGlowpad.startPing();} else {mGlowpad.stopPing();}}
    /*** Sets targets on the glowpad according to target set identified by the parameter.** @param targetSet Integer identifying the set of targets to use.*/@Overridepublic void showTargets(int targetSet, int videoState) {Log.d(this, "showTargets  targetSet  2 == " + targetSet);final int targetResourceId;final int targetDescriptionsResourceId;final int directionDescriptionsResourceId;final int handleDrawableResourceId;mGlowpad.setVideoState(videoState);switch (targetSet) {case TARGET_SET_FOR_AUDIO_WITH_SMS:targetResourceId = R.array.incoming_call_widget_audio_with_sms_targets;targetDescriptionsResourceId =R.array.incoming_call_widget_audio_with_sms_target_descriptions;directionDescriptionsResourceId =R.array.incoming_call_widget_audio_with_sms_direction_descriptions;handleDrawableResourceId = R.drawable.ic_incall_audio_handle;break;case TARGET_SET_FOR_VIDEO_WITHOUT_SMS:targetResourceId = R.array.incoming_call_widget_video_without_sms_targets;targetDescriptionsResourceId =R.array.incoming_call_widget_video_without_sms_target_descriptions;directionDescriptionsResourceId =R.array.incoming_call_widget_video_without_sms_direction_descriptions;handleDrawableResourceId = R.drawable.ic_incall_video_handle;break;.............省略部分代码;}

answer_fragment

<com.android.incallui.GlowPadWrapperxmlns:android="http://schemas.android.com/apk/res/android" //设置android原生的命名空间xmlns:dc="http://schemas.android.com/apk/res-auto"  //设置dc特殊的命名空间,这样后面dc:属性才可以识别android:id="@+id/glow_pad_view"android:layout_width="match_parent"android:layout_height="match_parent"android:focusable="true"android:layout_centerHorizontal="true"android:gravity="center"android:background="@color/glowpad_background_color"  //黑色android:layout_marginBottom="@dimen/glowpadview_margin_bottom"dc:targetDrawables="@array/incoming_call_widget_audio_with_sms_targets"  //显示各个方向上的图标dc:targetDescriptions="@array/incoming_call_widget_audio_with_sms_target_descriptions" //各个方向图标描述字符串dc:directionDescriptions="@array/incoming_call_widget_audio_with_sms_direction_descriptions" //各个方向的描述信息,指明这个方向可以做什么事dc:handleDrawable="@drawable/ic_incall_audio_handle"  //接听图标dc:outerRingDrawable="@drawable/ic_lockscreen_outerring"  //最外层的圆圈dc:outerRadius="@dimen/glowpadview_target_placement_radius"  //外圆半径dc:innerRadius="@dimen/glowpadview_inner_radius"  //内圆半径dc:snapMargin="@dimen/glowpadview_snap_margin"  //滑动时距离图标多远就算已达到图标,并且图标会变换dc:feedbackCount="1"  //动画播放的次数,GlowPadWrapper会重复播放动画,GlowPadView中也有默认值为3,代码逻辑判断只要这个值大于0就会播放动画,所以设不设置都会重复播放动画,知道touch事件主动调用停止dc:vibrationDuration="20"  //震动时长毫秒dc:glowRadius="@dimen/glowpadview_glow_radius" //以前版本的光晕半径,也就是当我们按下并移动时,跟随我们手指移动的那一小团小白点,但是现在的版本没有跟着手指移动的小白点了dc:pointDrawable="@drawable/ic_lockscreen_glowdot" //小白点资源dc:allowScaling="true"  //是否允许缩放这个圆 />

参考:http://blog.csdn.net/yihongyuelan/article/details/14000363 这个链接是4.2的版本有点老了,但是大致一样,有些细节不一样,不一样的地方上面的代码注释也有说明,可以对比查看。

GlowPadWrapper

这个类其实就是 GlowPadView 的包装,它起到一个中间层的作用,GlowPadAnswerFragment通过它来控制 GlowPadView 的动画启停,GlowPadView 通过它来反馈用户的 touch 和 select 事件给 AnswerFragment ,做对应的逻辑处理。

    private final Handler mPingHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case PING_MESSAGE_WHAT: //重复播放动画的msgtriggerPing();break;}}};private void triggerPing() {Log.d(this, "triggerPing(): " + mPingEnabled + " " + this);if (mPingEnabled && !mPingHandler.hasMessages(PING_MESSAGE_WHAT)) {ping(); //开始动画if (ENABLE_PING_AUTO_REPEAT) { //一直是true 所以动画会一直播放mPingHandler.sendEmptyMessageDelayed(PING_MESSAGE_WHAT, PING_REPEAT_DELAY_MS);}}@Override //GlowPadView 中当用户滑动到一个图标后触发的方法public void onTrigger(View v, int target) {Log.d(this, "onTrigger() view=" + v + " target=" + target);final int resId = getResourceIdForTarget(target);if (resId == R.drawable.ic_lockscreen_answer) {mAnswerFragment.onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext()); //接听电话mTargetTriggered = true;} else if (resId == R.drawable.ic_lockscreen_decline) {mAnswerFragment.onDecline(getContext()); //拒绝电话mTargetTriggered = true;} else if (resId == R.drawable.ic_lockscreen_text) {mAnswerFragment.onText(); //文本消息回复mTargetTriggered = true;} else if (resId == R.drawable.ic_videocam || resId == R.drawable.ic_lockscreen_answer_video) {mAnswerFragment.onAnswer(mVideoState, getContext()); //video状态下的接听mTargetTriggered = true;} else if (resId == R.drawable.ic_lockscreen_decline_video) {mAnswerFragment.onDeclineUpgradeRequest(getContext()); //拒绝升级请求mTargetTriggered = true;} else {// Code should never reach here.Log.e(this, "Trigger detected on unhandled resource. Skipping.");}}

GlowPadView

具体的 GlowPadView 的实现类,里面包含了view的绘画和动画的定义,还有一些监听和回调,这部分内容后面再做详细的分析。

LOG信息

01-11 10:29:48.872 D/InCall  ( 5589): AnswerPresenter - onIncomingCall: com.android.incallui.AnswerPresenter@95a864f
01-11 10:29:49.895 D/InCall  ( 5589): AnswerPresenter - Showing incoming for call id: Call_0 com.android.incallui.AnswerPresenter@95a864f
//界面的启动和初始化
01-11 10:29:49.962 D/InCall  ( 5589): GlowPadWrapper - class created com.android.incallui.GlowPadWrapper{ebc6975 VFED..... ......I. 0,0-0,0 #7f0a0094 app:id/glow_pad_view}
01-11 10:29:49.962 D/InCall  ( 5589): GlowPadWrapper - onFinishInflate()
01-11 10:29:49.967 D/InCall  ( 5589): GlowPadAnswerFragment - Creating view for answer fragment GlowPadAnswerFragment{f709f47 #2 id=0x7f0a00c4 tag_answer_fragment}
01-11 10:29:49.967 D/InCall  ( 5589): GlowPadAnswerFragment - Created from activitycom.android.incallui.InCallActivity@494e8d4
//界面显示和动画
01-11 10:29:49.968 D/InCall  ( 5589): GlowPadAnswerFragment - Show answer UI: true
01-11 10:29:49.968 D/InCall  ( 5589): GlowPadWrapper - startPing
01-11 10:29:49.968 D/InCall  ( 5589): GlowPadWrapper - triggerPing(): true com.android.incallui.GlowPadWrapper{ebc6975 VFED..... ......I. 0,0-0,0 #7f0a0094 app:id/glow_pad_view}
01-11 10:29:49.973 D/InCall  ( 5589): GlowPadAnswerFragment - showTargets  targetSet  1 == 1
01-11 10:29:49.973 D/InCall  ( 5589): GlowPadAnswerFragment - showTargets  targetSet  2 == 1
01-11 10:29:49.974 D/InCall  ( 5589): AnswerPresenter - getVideoUpgradeRequestCall call =null

AccessibleAnswerFragment

这个界面是Android 7.0 新加入的界面,主要是给有生理障碍的人士使用,在 InCallActivity 里面通过判断是否启动无障碍功能里面的 TalkBack 服务,来决定是否显示 AccessibleAnswerFragment

            if (AccessibilityUtil.isTalkBackEnabled(this)) { //如果开启就启动AccessibleAnswerFragment 界面mAnswerFragment = new AccessibleAnswerFragment();} else {//否则启动 GlowPadAnswerFragment 界面mAnswerFragment = new GlowPadAnswerFragment();}

界面图片

可以看到这个界面相对于 GlowPadAnswerFragment 界面就简单得多了,只有三个 imageview 没有复杂的动画在里面。

AccessibleAnswerFragment

这个类的主要作用就是监听并处理用户的点击和滑动事件,从而调用 AnswerFragment 里面的接听、挂断、短信回复这些方法。相关的方法如下:

//设置点击事件,通过三个view来触发不同的应答逻辑mAnswer = group.findViewById(R.id.accessible_answer_fragment_answer);mAnswer.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "Answer Button Clicked");onAnswer(VideoProfile.STATE_AUDIO_ONLY, getContext());}});mDecline = group.findViewById(R.id.accessible_answer_fragment_decline);mDecline.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "Decline Button Clicked");onDecline(getContext());}});mText = group.findViewById(R.id.accessible_answer_fragment_text);mText.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "Text Button Clicked");onText();}});//设置滑动事件的监听,通过滑动方向来确定应答模式private boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {if (hasPendingDialogs()) {return false;}float diffY = e2.getY() - e1.getY();float diffX = e2.getX() - e1.getX();if (Math.abs(diffX) > Math.abs(diffY)) {if (Math.abs(diffX) > SWIPE_THRESHOLD) {if (diffX > 0) {onSwipeRight();} else {onSwipeLeft();}}return true;} else if (Math.abs(diffY) > SWIPE_THRESHOLD) {if (diffY > 0) {onSwipeDown();} else {onSwipeUp();}return true;}return false;}//设置touch监听为全屏事件,即整个 InCallActivity 界面@Overridepublic void onResume() {super.onResume();// Intercept all touch events for full screen swiping gesture.InCallActivity activity = (InCallActivity) getActivity();activity.setDispatchTouchEventListener(mTouchListener);}//touch监听事件即为我们的 滑动事件监听,所以我们可以在全屏任何地方滑动触发相关逻辑代码private class TouchListener implements View.OnTouchListener {@Overridepublic boolean onTouch(View v, MotionEvent event) {return mGestureDetector.onTouchEvent(event);}}

accessible_answer_fragment

这个文件是 GlowPadAnswerFragment 的布局文件,里面内容也很简单,通过相对布局和线性布局来得到我们上图下半部分的来电界面.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center_horizontal"android:background="@color/glowpad_background_color"><RelativeLayout
        android:id="@+id/accessible_answer_fragment_answer"android:orientation="vertical"android:layout_width="120dp"android:layout_height="120dp"android:focusable="true"android:focusableInTouchMode="true"android:clickable="true"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginLeft="16dp"android:layout_marginRight="16dp"><ImageView
            android:layout_width="64dp"android:layout_height="64dp"android:src="@drawable/ic_lockscreen_answer_activated_layer"android:layout_centerInParent="true"></ImageView><TextView
            android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/description_target_answer"android:textSize="12sp"android:textColor="@color/accessible_answer_hint_text_color"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:layout_marginBottom="8dp"/></RelativeLayout>.....省略部分代码

总结

  1. 来电界面有两个,一个是正常的 GlowPadAnswerFragment 一个是无障碍服务开启后显示的 AccessibleAnswerFragment (这个是7.0 新加的 fragment 通过判读 TalkBack 服务是否开启来决定是否显示这个fragment)
  2. GlowPadAnswerFragment 显示的其实就是 GlowPadView 这个自定义view

Android N 来电界面相关推荐

  1. Android自定义来电界面实现

    场景需求 在手机来电时,有时不方便接听电话,希望能点触屏幕达到静音的效果,稍候再接听电话. 开发思路 首先得获得手机来电的事件,进而监听屏幕的点击事件,让手机铃声静音 困难点 手机来电事件,是系统中优 ...

  2. Android 仿通话来电界面

    Android 仿通话来电界面 简介: 开发中需要模拟来电时的通话界面,仿照来电界面实现来电时播放铃声,界面通过动画模拟来电动效. 效果图: 自定义图片背景,图片由小变大的动态效果. shap_cir ...

  3. Android 号码, 来电归属地 Jni 使用C++对二进制文件查询(一) 理论篇

    1.效果图 左边的是应用程序界面,只是做个测试.右边的是应用程序信息,你会发现数据这块很小,只有420KB,要知道里面有近280,000记录. 2.尝试使用sqlite数据库, 用db格式文件. 随便 ...

  4. Android N 来电流程(MT)

    本流程图基于MTK平台 Android 7.0,普通来电,本流程只作为沟通学习使用 本篇文章写作顺序是从modem上报消息,一层一层上报到incallUI,读者可以根据需求选择阅读顺序. framew ...

  5. andriod 自定义来电界面功能实现的一些思考

    转载:http://blog.csdn.net/likebamboo/article/details/14449881 由于近期所做一个项目需要做类似于"来电秀"的功能,所以上网搜 ...

  6. andriod 自定义来电界面功能实现的一些思考。

    原创博文,转载请注明出处:http://blog.csdn.net/likebamboo/article/details/14449881 由于近期所做一个项目需要做类似于"来电秀" ...

  7. android的webView的教程,Android WebView 应用界面开发教程

    WebView组件本身就是一个浏览器实现,Android5.0增强的WebView基于Chromium M37,直接支持WebRTC.WebAudio.WebGL.开发者可以直接在WebView中使用 ...

  8. android图片跳转动画效果,Android实现Activity界面切换添加动画特效的方法

    本文以实例形式展示了Android实现Activity界面切换添加动画特效的方法,对于Android程序设计人员来说有很好的参考借鉴价值.具体方法如下: 了解Android程序设计的人应该知道,在An ...

  9. Android之登录界面设计

    Android之登录界面设计 这篇文章主要讲述Android开发中常用的APP开发界面–登录界面的开发(由于博主是初学安卓,可能有些小伙伴会感到简陋,我会继续努力学习新知识的,大家一起加油). (1) ...

最新文章

  1. IE6 浮动层背景不显示
  2. Android apk动态加载机制的研究
  3. .gitignore文件将已经纳入版本管理的文件删除
  4. vue如何引入ant部分组件
  5. Spring boot admin 升级到2.3.1 遇到的问题总结
  6. 【英语学习】【Level 07】U05 Best Destination L5 Top choice
  7. Java String类的intern()方法
  8. 自学JAVA-11:IO流
  9. html新的页面打开新页面,javascript如何打开新窗口?
  10. 对算法的认识——逻辑回归
  11. 阿里云主机的公网带宽和私网带宽的介绍
  12. 前端-CSS样式的简单介绍
  13. 键盘之争:QWERTY还是Dvorak
  14. 使用代理后,Onedrive发生了错误:0x80190001的解决办法
  15. 龙芯(mips)+麒麟V10 electron适配
  16. SDU软件17级大一下离散期末真题(回忆版)
  17. PDF设置密码保护的两种方法
  18. AvosCloud的文件存储 Demo
  19. Windows XP 进程分类(必要,需要,不要)windows xp 必要进程
  20. Python十分钟制作属于你自己的个性logo

热门文章

  1. 华南理工统考计算机应用基础,华南理工大学计算机应用基础平时作业
  2. Centos防火墙开启端口
  3. android+蓝牙传输文件,在Android中使用蓝牙的消息和文件传输
  4. 网易云音乐/QQ音乐API更新,支持多音质切换/MV获取
  5. 中企动力携手河南卫特解锁网络营销新模式
  6. 旋转接头的组成部分和密封方法
  7. 无线路由器媒体服务器怎么用,TP-LINK无线路由器网络存储共享的使用方法有哪些...
  8. 大家一起来讨论:Filecoin 经济模型和商业启示
  9. 郑州公交查询系统数据配置页面
  10. 胸有成竹——各类路由器默认密码一览(转)