Android4.2 keyguard源码架构,学习(一)!

最近这两年爱上写博客,是因为它可以很好的帮我理顺思路,特别是问题有点复杂的时候,很容易就陷进去。

首先用hierarchyviewer.bat查看当前界面的结构,找到突破口,然后慢慢找。

MediatekGlowPadView.java

KeyguardViewManager.java

KeyguardSelectorView.java

KeyguardHostView.java

KeyguardViewMediator.java

SlidingChallengeLayout.java

 既然是java语言写的,那肯定得一面向对象得思路来分析,对象从小到大。MediatekGlowPadView对象首先是view的派生类,负责用来显示,并且监听touch事件。

官方解释:一个可重用widget,包含一个中心,外圈和波浪动画。

public class MediatekGlowPadView extends View implements OnTouchListener {
}
截图明了:




首先看下构造函数:

主要就是初始化一些参数,例如圈的半径之类的。这里记录一个基础性的问题:

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GlowPadView);
        mInnerRadius = a.getDimension(R.styleable.GlowPadView_innerRadius, mInnerRadius);
    prvandroid:innerRadius="@*android:dimen/glowpadview_inner_radius"

styleable后面首先要接style的类型,下划线然后接具体的属性(GlowPadView_innerRadius)。

对于此类中比较生疏的有:tween动画效果

另外例一下对分析这个对象有很大帮助的重要函数:switchToState()   onTouchEvent()    handleTrigger()。

    private void handleTrigger(LockScreenNewEventView newEventView) {
        ///M: In case unlock blocks newly launched activity, we should direct ueser to unlock mode first
        if (mOnTriggerListener != null) {
            mOnTriggerListener.onTrigger(newEventView, -1);
        }
        Intent intent = new Intent();
        int resourceId = newEventView.getResourceId();
        switch (resourceId) {
            case com.mediatek.internal.R.drawable.ic_newevent_smsmms:
                intent.setComponent(new ComponentName(MMS_PACKAGE_NAME, MMS_CLASS_NAME));
                launchActivity(intent);
                break;
            case com.mediatek.internal.R.drawable.ic_newevent_phone:
                intent.setComponent(new ComponentName(CALL_LOG_PACKAGE_NAME, CALL_LOG_CLASS_NAME));
                launchActivity(intent);
                break;
            case com.mediatek.internal.R.drawable.ic_newevent_email:
                intent.setComponent(new ComponentName(EMAIL_PACKAGE_NAME, EMAIL_CLASS_NAME));
                launchActivity(intent);
                break;
            default:
                Xlog.d(TAG, "handleTrigger unknown resource id, resourceId=" + resourceId);
        }
    }

这里运用了典型的策略和机制分离思想。(可能有人会误解,上面代码中的实现机制是没有实际作用的,摆设),mOnTriggerListener.onTrigger(newEventView, -1)监听接口,实现是在KeyguardSelectorView.java文件中。


KeyguardSelectorView:这是整个主锁屏界面对象,不包含左右滑动的页面。除了上面的解锁图标外,还有一些其他显示信息,例如:sim信息,闹钟等


监听对象的实现:

    MediatekGlowPadView.OnTriggerListener mOnTriggerListener = new MediatekGlowPadView.OnTriggerListener() {

        public void onTrigger(View v, int target) {
            final int resId = mGlowPadView.getResourceIdForTarget(target);
            switch (resId) {
                case com.android.internal.R.drawable.ic_action_assist_generic:
                    Intent assistIntent =
                            ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
                            .getAssistIntent(mContext, UserHandle.USER_CURRENT);
                    if (assistIntent != null) {
                        mActivityLauncher.launchActivity(assistIntent, false, true, null, null);
                    } else {
                        Log.w(TAG, "Failed to get intent for assist activity");
                    }
                    mCallback.userActivity(0);
                    break;

                case com.android.internal.R.drawable.ic_lockscreen_camera:
                    mActivityLauncher.launchCamera(null, null);
                    mCallback.userActivity(0);
                    break;

                case com.android.internal.R.drawable.ic_lockscreen_phone:
		   Intent phoneIntent = new Intent();
                     phoneIntent.setComponent(new ComponentName("com.android.contacts", 
                                                                         "com.android.contacts.activities.DialtactsActivity")); 	
		   mActivityLauncher.launchActivity(phoneIntent, false, false, null, null);
                    mCallback.userActivity(0);
                    break;
                case com.android.internal.R.drawable.ic_lockscreen_sms:
		   Intent smsIntent = new Intent();
                     smsIntent.setComponent(new ComponentName("com.android.mms", 
                                                                         "com.android.mms.ui.BootActivity")); 	
		   mActivityLauncher.launchActivity(smsIntent, false, false, null, null);
                    mCallback.userActivity(0);
                    break;			

                case com.android.internal.R.drawable.ic_lockscreen_unlock_phantom:
                case com.android.internal.R.drawable.ic_lockscreen_unlock:
                    mCallback.userActivity(0);
                    mCallback.dismiss(false);
                    break;
                    
                /// M: Add a special case for incoming indicator feature, when indicator view launches activity, go to unlockscreen
                /// only if necessary, or you may see homescreen before activity is launched
                case -1:
                    mCallback.userActivity(0);
                    if (isSecure()) {
                        mCallback.dismiss(false);
                    }
                break;
            }
        }
………………
    }

构造函数:很简单,就是实例化一个锁屏图形,LockPatternUtils。

主要ui显示:

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mGlowPadView = (MediatekGlowPadView) findViewById(R.id.glow_pad_view);
        mGlowPadView.setOnTriggerListener(mOnTriggerListener);
        updateTargets();

        mSecurityMessageDisplay = new KeyguardMessageArea.Helper(this);
        View bouncerFrameView = findViewById(R.id.keyguard_selector_view_frame);
        mBouncerFrame = bouncerFrameView.getBackground();
        
        /// M: If dm lock is on, we should also hide widget @{
        boolean dmLocked = KeyguardUpdateMonitor.getInstance(getContext()).dmIsLocked();
        mGlowPadView.setVisibility(dmLocked ? View.INVISIBLE : View.VISIBLE);
        /// @}
        
        /// M: Init medaitke newevent feature related views
        if (Settings.System.getInt(getContext().getContentResolver(), INCOMING_INDICATOR_ON_LOCKSCREEN, 1) == 1) {
            Log.d(TAG, "constructor infalte newevent feature related views");
            mGlowPadView.setLockScreenView(this);
            ViewGroup unLockPanel = (ViewGroup)findViewById(R.id.keyguard_unlock_panel);
            final LayoutInflater inflater = LayoutInflater.from(mContext);
            inflater.inflate(com.mediatek.internal.R.layout.keyguard_unread_event_view, unLockPanel, true);
            UnReadEventView unReadEventView = (UnReadEventView)findViewById(com.mediatek.internal.R.id.unread_event_view);
            /// M: Incoming Indicator for Keyguard Rotation @{
            unReadEventView.setVisibility(dmLocked ? View.INVISIBLE : View.VISIBLE);
            unReadEventView.updateQueryBaseTimeAndRefreshUnReadNumber(KeyguardUpdateMonitor.getInstance(mContext).getQueryBaseTime());
            /// @}
            setUnReadEventView(unReadEventView);
            mGlowPadView.syncUnReadEventView(unReadEventView);
        }
    }

应用glow_pad_view.xml的布局,一般自定四个方向的解锁功能和图标,就从这里来找了。

开启监听。

另外这里总结一个现象,子界面的xml布局文件一般是在父界面调用。例如上面在KeyguardSelectorView中调用glow_pad_view.xml(对应MediatekGlowPadView)。

对应的Keyguard_selector_view.xml 布局文件:

<com.android.internal.policy.impl.keyguard.KeyguardSelectorView
    xmlns:prvandroid="http://schemas.android.com/apk/prv/res/android"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyguard_selector_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_maxWidth="500dp"
    android:layout_maxHeight="@dimen/keyguard_security_height"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:orientation="vertical"
    android:contentDescription="@string/keyguard_accessibility_slide_unlock">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:gravity="center">

        <include layout="@layout/keyguard_message_area"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <View
            android:id="@+id/keyguard_selector_view_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:background="@*android:drawable/kg_bouncer_bg_white"/>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="20dp"
            android:id="@+id/keyguard_unlock_panel">
            <include layout="@layout/keyguard_glow_pad_container" />
        </FrameLayout>

        <include layout="@layout/keyguard_eca"
            android:id="@+id/keyguard_selector_fade_container"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_gravity="bottom|center_horizontal" />
    </FrameLayout>

</com.android.internal.policy.impl.keyguard.KeyguardSelectorView>

上面XmL文件可以很直观的看到布局界面,其中keyguard_unlock_panel就是glow_pad_view.xml的应用。

因为我这里主要是为了了解锁屏的架构,所以对其他的布局不做分析。

因为keyguard_selector_view.xml在KeyguardHostView中调用,接下来分析这个文件。

KeyguardHostView:这个三个keyguard界面对象。包含appwidget


首先看一下整体布局,keyguard_host_view.xml,这里分为port和land,port是SlidingChallengeLayout,land是MultiPaneChallengeLayout,下面我们以port为例分析:

<com.android.internal.policy.impl.keyguard.KeyguardHostView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyguard_host_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <com.android.internal.policy.impl.keyguard.SlidingChallengeLayout
        android:id="@+id/sliding_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            androidprv:layout_childType="mediatekLayerBackground">
        </FrameLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            androidprv:layout_childType="pageDeleteDropTarget">
            <include layout="@layout/keyguard_widget_remove_drop_target"
                android:id="@+id/keyguard_widget_pager_delete_target"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="top|center_horizontal" />
        </FrameLayout>

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            androidprv:layout_childType="widgets">
            <include layout="@layout/keyguard_widget_pager"
                android:id="@+id/app_widget_container"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"/>
        </FrameLayout>

        <View android:layout_width="match_parent"
              android:layout_height="match_parent"
              androidprv:layout_childType="scrim"
              android:background="#99000000" />
        
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            androidprv:layout_childType="mediatekLayerForeground">
        </FrameLayout>

        <com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer
            android:id="@+id/keyguard_security_container"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_maxHeight="@dimen/keyguard_security_height"
            androidprv:layout_childType="challenge"
            android:padding="0dp"
            android:gravity="bottom|center_horizontal">
            <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
                android:id="@+id/view_flipper"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipToPadding="false"
                android:paddingTop="@dimen/keyguard_security_view_margin"
                android:gravity="center">
            </com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper>
        </com.android.internal.policy.impl.keyguard.KeyguardSecurityContainer>

        <ImageButton
              android:layout_width="match_parent"
              android:layout_height="@dimen/kg_widget_pager_bottom_padding"
              androidprv:layout_childType="expandChallengeHandle"
              android:focusable="true"
              android:background="@null"
              android:src="@drawable/keyguard_expand_challenge_handle"
              android:scaleType="center"
              android:contentDescription="@string/keyguard_accessibility_expand_lock_area" />

    </com.android.internal.policy.impl.keyguard.SlidingChallengeLayout>
</com.android.internal.policy.impl.keyguard.KeyguardHostView>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值