最近这两年爱上写博客,是因为它可以很好的帮我理顺思路,特别是问题有点复杂的时候,很容易就陷进去。
首先用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>