Android7.0 InCallUI 源码分析

 

Android7.0 InCallUI 源码分析

AndroidManifest.xml

源码路径:packages\apps\Dialer\InCallUI  

注:android7.0之前packages\apps\InCallUI

InCallUI\AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

        package="com.android.incallui">

    <uses-sdk

        android:minSdkVersion="23"

        android:targetSdkVersion="23" />

</manifest>

 

InCallUI的组件声明在Dialer\AndroidManifest.xml

<!-- Main in-call UI activity.  This is never launched directly from outside the phone app; instead, it's either launched by the OutgoingCallBroadcaster (for outgoing calls), or as the fullScreenIntent of a notification (for incoming calls.) -->

IncallActivity不能通过外部APP直接启动,只能通过广播的方式启动,或者是能全屏的通知(比如:来电)

<activity android:name="com.android.incallui.InCallActivity"

   android:theme="@style/Theme.InCallScreen"

   android:label=""

   android:excludeFromRecents="true"

   android:launchMode="singleInstance"                 

android:configChanges="smallestScreenSize|screenLayout|keyboardHidden"

   android:exported="false"

   android:screenOrientation="nosensor"

   android:directBootAware="true"

   android:resizeableActivity="true">

</activity>

 

// android:excludeFromRecents="true"  不让activity显示在Recent screens中

所以要想属性生效设置该属性的 Activity 必须是 Task 的根 Activity。如果在某个 Task 非根 Activity 中设置 android:excludeFromRecents 是没有任何效果的。

// android:screenOrientation="nosensor"  不受重力感应横竖屏切换

// android:directBootAware="true" 

在此 Direct Boot Mode 下 APP 比较适合做一些:

  • Alarm、clock 类的操作
  • 需要做重要的或紧急的通知
  • 底层服务类

    使用场景,比如手机丢了,捡到的人解不开锁,也做不了啥操作,现在任意工作在Direct Boot Mode 下的APP都可以“安全地”跑起来,和服务器建链,更加全方位的和捡手机的人进行沟通。更多的场景还需要更大的脑洞。

APP在进入DBM 后会收到系统的广播消息: Intent.ACTION_LOCKED_BOOT_COMPLETED —— 新增的。

用户解锁手机后,APP会收到另一条: Intent.ACTION_BOOT_COMPLETED —— 一直都有

// android:resizeableActivity="true" 支持分屏任务,android7.0以下不能设置该属性

 

InCallActivity

packages\apps\Dialer\InCallUI\src\com\android\incallui\InCallActivity.java

布局解析

InCallActivity的根布局

//  setContentView(R.layout.incall_screen);

incall_screen.xml

<!-- In-call Phone UI; see InCallActivity.java. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:id="@+id/main" >
</FrameLayout>

IncallActivity的布局相对复杂,静态布局和动态布局相结合,下文会介绍CallCardFragment。

相关类图

类图说明:InCallActivity继承了TransactionSafeActivity,IncallActivity类负责UI展示,InCallPresenter是InCallActivity的代理类,负责相关的逻辑处理,通过回调与InCallActivity进行交互。

 

InCallActivity的 onCreate()方法中添加了亮屏、悬浮锁屏界面,过滤无关的触摸事件的Flag

// set this flag so this activity will stay in front of the keyguard
        // Have the WindowManager filter out touch events that are "too fat".
        int flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;

        getWindow().addFlags(flags);

InCallActivity中相关Fragment如下:

    private CallButtonFragment mCallButtonFragment;
    private CallCardFragment mCallCardFragment;
    private AnswerFragment mAnswerFragment;
    private DialpadFragment mDialpadFragment;
    private ConferenceManagerFragment mConferenceManagerFragment;
    
    ...
    ...
    // CallCardFragment 
    boolean showContactPhoto = !VideoCallPresenter.showIncomingVideo(videoState, state);

CallCardFragment:用于显示联系人信息及通话时间等;
CallButtonFragment:通话界面下方的控制按钮。
DialpadFragment:拨号盘显示控件。
AnswerFragment:来电控制控件,用于操作接听/拒接/短信快捷回复。
ConferenceManagerFragment:会议电话的界面。
VideoCallFragment:视屏通话控件,在CallCardFragment中调用。

 

private void showFragment(String tag, boolean show, boolean executeImmediately) {

        Trace.beginSection("showFragment - " + tag);

        final FragmentManager fm = getFragmentManagerForTag(tag);


        if (fm == null) {

            Log.w(TAG, "Fragment manager is null for : " + tag);

            return;

        }

        Fragment fragment = fm.findFragmentByTag(tag);

        if (!show && fragment == null) {

            // Nothing to show, so bail early.

            return;

        }


        final FragmentTransaction transaction = fm.beginTransaction();

        if (show) {

            if (fragment == null) {

                fragment = createNewFragmentForTag(tag);

                transaction.add(getContainerIdForFragment(tag), fragment, tag);

            } else {

                transaction.show(fragment);

            }

            Logger.logScreenView(getScreenTypeForTag(tag), this);

        } else {

            transaction.hide(fragment);

        }

        transaction.commitAllowingStateLoss();

        if (executeImmediately) {

            fm.executePendingTransactions();

        }

        Trace.endSection();

    }

通过tag懒加载Fragment

private Fragment createNewFragmentForTag(String tag) {
        if (TAG_DIALPAD_FRAGMENT.equals(tag)) {
            mDialpadFragment = new DialpadFragment();
            return mDialpadFragment;
        } else if (TAG_ANSWER_FRAGMENT.equals(tag)) {
            if (AccessibilityUtil.isTalkBackEnabled(this)) {
                mAnswerFragment = new AccessibleAnswerFragment();
            } else {
                mAnswerFragment = new GlowPadAnswerFragment();
            }
            return mAnswerFragment;
        } else if (TAG_CONFERENCE_FRAGMENT.equals(tag)) {
            mConferenceManagerFragment = new ConferenceManagerFragment();
            return mConferenceManagerFragment;
        } else if (TAG_CALLCARD_FRAGMENT.equals(tag)) {
            mCallCardFragment = new CallCardFragment();
            return mCallCardFragment;
        }
        throw new IllegalStateException("Unexpected fragment: " + tag);
    }

 

CallCardFragment

packages\apps\Dialer\InCallUI\src\com\android\incallui\CallCardFragment.java

InCallActivity中的几个fragment都继承了BaseFragment,每个Fragment都有一个Presenter(降低代码耦合性); BaseFragment、Presenter都采用了泛型设计:

Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

CallCardFragment的关系类图如下:

public abstract class BaseFragment<T extends Presenter<U>, U extends Ui> extends Fragment{};其中几个重要的方法有


    
    public abstract T createPresenter();

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值