您的位置:首页 > 移动开发 > Android开发

AndroidICS4.0---->LockScreen锁屏流程【Android源码解析九】

2012-07-19 09:35 495 查看


转载:http://blog.csdn.net/wdaming1986/article/details/7753206


先来说说LockScreen分类;

一、无锁屏;

二、锁屏:

1、UnLockScreen:

图案锁、 PIN锁, 密码锁;

2、LockScreen:

波纹锁;

有图有真相------>





接着我们来看看LockScreen的时序图:



综上所述:

1、createUnlockScreenFor()方法创建的是UnLockScreen界面,代码如下:

[java]
view plaincopyprint?

View createUnlockScreenFor(UnlockMode unlockMode) {
View unlockView = null;

if (DEBUG) Log.d(TAG,
"createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback);

if (unlockMode == UnlockMode.Pattern) {
PatternUnlockScreen view = new PatternUnlockScreen(
mContext,
mConfiguration,
mLockPatternUtils,
mUpdateMonitor,
mKeyguardScreenCallback,
mUpdateMonitor.getFailedAttempts());
view.setEnableFallback(mEnableFallback);
unlockView = view;
} else if (unlockMode == UnlockMode.SimPuk) {
unlockView = new SimPukUnlockScreen(
mContext,
mConfiguration,
mUpdateMonitor,
mKeyguardScreenCallback,
mLockPatternUtils, MSimTelephonyManager.getDefault().getDefaultSubscription());
} else if (unlockMode == UnlockMode.SimPin) {
unlockView = new SimUnlockScreen(
mContext,
mConfiguration,
mUpdateMonitor,
mKeyguardScreenCallback,
mLockPatternUtils);
} else if (unlockMode == UnlockMode.Account) {
try {
unlockView = new AccountUnlockScreen(
mContext,
mConfiguration,
mUpdateMonitor,
mKeyguardScreenCallback,
mLockPatternUtils);
} catch (IllegalStateException e) {
Log.i(TAG, "Couldn't instantiate AccountUnlockScreen"
+ " (IAccountsService isn't available)");
// TODO: Need a more general way to provide a
// platform-specific fallback UI here.
// For now, if we can't display the account login
// unlock UI, just bring back the regular "Pattern" unlock mode.

// (We do this by simply returning a regular UnlockScreen
// here. This means that the user will still see the
// regular pattern unlock UI, regardless of the value of
// mUnlockScreenMode or whether or not we're in the
// "permanently locked" state.)
return createUnlockScreenFor(UnlockMode.Pattern);
}
} else if (unlockMode == UnlockMode.Password) {
unlockView = new PasswordUnlockScreen(
mContext,
mConfiguration,
mLockPatternUtils,
mUpdateMonitor,
mKeyguardScreenCallback);
} else {
throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
}
initializeTransportControlView(unlockView);
initializeFaceLockAreaView(unlockView); // Only shows view if FaceLock is enabled

mUnlockScreenMode = unlockMode;
return unlockView;
}

2、createLockScreen()就是创建LockScreen界面:

[java]
view plaincopyprint?

View createLockScreen() {
/*View lockView = new LockScreen(
mContext,
mConfiguration,
mLockPatternUtils,
mUpdateMonitor,
mKeyguardScreenCallback);
initializeTransportControlView(lockView);
return lockView;*/

long lockscreenType = 0;
try{
lockscreenType = android.provider.Settings.Secure.
getLong(mContext.getContentResolver(), "lockscreen.disabled");
}catch(Exception e){
e.printStackTrace();
}
View lockView = null;
lockView = new LockScreen(
mContext,
mConfiguration,
mLockPatternUtils,
mUpdateMonitor,
mKeyguardScreenCallback);
initializeTransportControlView(lockView);
return lockView;
}

我们来看看锁屏界面的流程:

step 1:创建LockScreen.java类——>先看看构造函数:

[java]
view plaincopyprint?

LockScreen(Context context, Configuration configuration, LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor updateMonitor,
KeyguardScreenCallback callback) {
super(context);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = updateMonitor;
mCallback = callback;

mEnableMenuKeyInLockScreen = shouldEnableMenuKey();

mCreationOrientation = configuration.orientation;

mKeyboardHidden = configuration.hardKeyboardHidden;

if (LockPatternKeyguardView.DEBUG_CONFIGURATION) {
Log.v(TAG, "***** CREATING LOCK SCREEN", new RuntimeException());
Log.v(TAG, "Cur orient=" + mCreationOrientation
+ " res orient=" + context.getResources().getConfiguration().orientation);
}

final LayoutInflater inflater = LayoutInflater.from(context);
if (DBG) Log.v(TAG, "Creation orientation = " + mCreationOrientation);
if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) {
inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true);
} else {
inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true);
}

if (TelephonyManager.getDefault().isMultiSimEnabled()) {
mStatusViewManager = new MSimKeyguardStatusViewManager(this, mUpdateMonitor,
mLockPatternUtils, mCallback, false);
} else {
mStatusViewManager = new KeyguardStatusViewManager(this, mUpdateMonitor,
mLockPatternUtils, mCallback, false);
}

setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);

mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
// modify by wangxianming in 2012-06-22
if (mAudioManager != null) {
mSilentMode = isSilentMode();
}

mUnlockWidget = findViewById(R.id.unlock_widget);
if (mUnlockWidget instanceof SlidingTab) {
SlidingTab slidingTabView = (SlidingTab) mUnlockWidget;
slidingTabView.setHoldAfterTrigger(true, false);
slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label);
slidingTabView.setLeftTabResources(
R.drawable.ic_jog_dial_unlock,
R.drawable.jog_tab_target_green,
R.drawable.jog_tab_bar_left_unlock,
R.drawable.jog_tab_left_unlock);
SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView);
slidingTabView.setOnTriggerListener(slidingTabMethods);
mUnlockWidgetMethods = slidingTabMethods;
} else if (mUnlockWidget instanceof WaveView) {
WaveView waveView = (WaveView) mUnlockWidget;
WaveViewMethods waveViewMethods = new WaveViewMethods(waveView);
waveView.setOnTriggerListener(waveViewMethods);
mUnlockWidgetMethods = waveViewMethods;
} else if (mUnlockWidget instanceof MultiWaveView) {
MultiWaveView multiWaveView = (MultiWaveView) mUnlockWidget;
MultiWaveViewMethods multiWaveViewMethods = new MultiWaveViewMethods(multiWaveView);
multiWaveView.setOnTriggerListener(multiWaveViewMethods);
mUnlockWidgetMethods = multiWaveViewMethods;
} else {
throw new IllegalStateException("Unrecognized unlock widget: " + mUnlockWidget);
}

// Update widget with initial ring state
mUnlockWidgetMethods.updateResources();

if (DBG) Log.v(TAG, "*** LockScreen accel is "
+ (mUnlockWidget.isHardwareAccelerated() ? "on":"off"));
}

Step 2:在Step 1步骤中根据横竖屏来加载横竖屏的布局:

[java]
view plaincopyprint?

if (mCreationOrientation != Configuration.ORIENTATION_LANDSCAPE) {
inflater.inflate(R.layout.keyguard_screen_tab_unlock, this, true);
} else {
inflater.inflate(R.layout.keyguard_screen_tab_unlock_land, this, true);
}

Step 3:来看看竖屏的布局文件的代码:

[java]
view plaincopyprint?

<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<!-- 锁屏界面加载数字时钟 -->
<com.android.internal.widget.DigitalClock android:id="@+id/time"
android:layout_marginTop="@dimen/keyguard_lockscreen_status_line_clockfont_top_margin"
android:layout_marginBottom="12dip"
android:layout_marginRight="@dimen/keyguard_lockscreen_status_line_font_right_margin"
android:layout_gravity="right">

<!-- Because we can't have multi-tone fonts, we render two TextViews, one on
top of the other. Hence the redundant layout... -->
<TextView android:id="@+id/timeDisplayBackground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="none"
android:textSize="@dimen/keyguard_lockscreen_clock_font_size"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_marginBottom="6dip"
android:textColor="@color/lockscreen_clock_background"
/>

<TextView android:id="@+id/timeDisplayForeground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="none"
android:textSize="@dimen/keyguard_lockscreen_clock_font_size"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_marginBottom="6dip"
android:textColor="@color/lockscreen_clock_foreground"
android:layout_alignLeft="@id/timeDisplayBackground"
android:layout_alignTop="@id/timeDisplayBackground"
/>

</com.android.internal.widget.DigitalClock>

<LinearLayout
android:orientation="horizontal"
android:layout_gravity="right"
android:layout_marginRight="@dimen/keyguard_lockscreen_status_line_font_right_margin">
<!-- 锁屏界面加载日期 -->
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/keyguard_lockscreen_status_line_font_size"
/>
<!-- 锁屏界面加载闹钟状态 -->
<TextView
android:id="@+id/alarm_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dip"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/keyguard_lockscreen_status_line_font_size"
android:drawablePadding="4dip"
/>

</LinearLayout>
<!-- 锁屏界面加载充电状态 -->
<TextView
android:id="@+id/status1"
android:layout_gravity="right"
android:layout_marginRight="@dimen/keyguard_lockscreen_status_line_font_right_margin"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/keyguard_lockscreen_status_line_font_size"
android:drawablePadding="4dip"
/>

<Space android:layout_gravity="fill" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="302dip">
<!-- 锁屏界面加载波纹的锁屏 -->
<com.android.internal.widget.multiwaveview.MultiWaveView
android:id="@+id/unlock_widget"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"

android:targetDrawables="@array/lockscreen_targets_with_camera"
android:targetDescriptions="@array/lockscreen_target_descriptions_with_camera"
android:directionDescriptions="@array/lockscreen_direction_descriptions"
android:handleDrawable="@drawable/ic_lockscreen_handle"
android:waveDrawable="@drawable/ic_lockscreen_outerring"
android:outerRadius="@dimen/multiwaveview_target_placement_radius"
android:snapMargin="@dimen/multiwaveview_snap_margin"
android:hitRadius="@dimen/multiwaveview_hit_radius"
android:rightChevronDrawable="@drawable/ic_lockscreen_chevron_right"
android:horizontalOffset="0dip"
android:verticalOffset="60dip"
android:feedbackCount="3"
android:vibrationDuration="20"
/>
<!-- 锁屏界面加载运营商状态 -->
<TextView
android:id="@+id/carrier"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="12dip"
android:gravity="center_horizontal"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/keyguard_lockscreen_status_line_font_size"
android:textColor="?android:attr/textColorSecondary"
/>

</RelativeLayout>

<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
style="?android:attr/buttonBarStyle"
android:gravity="center"
android:weightSum="2">
<!-- 锁屏界面加载紧急拨号按钮 -->
<Button android:id="@+id/emergencyCallButton"
android:layout_gravity="center_horizontal"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
style="?android:attr/buttonBarButtonStyle"
android:textSize="@dimen/keyguard_lockscreen_status_line_font_size"
android:text="@*android:string/lockscreen_emergency_call"
android:drawableLeft="@*android:drawable/lockscreen_emergency_button"
android:drawablePadding="0dip"
android:visibility="gone"
/>

</LinearLayout>

</GridLayout>

Step 4:在Step 3中重点看com.android.internal.widget.multiwaveview.MultiWaveView这个自定义的view,这个view是处理ICS4.0锁屏的拖拽的功能,具体代码如下:

[java]
view plaincopyprint?

public MultiWaveView(Context context, AttributeSet attrs) {
super(context, attrs);
Resources res = context.getResources();
。。。 。。。
加载资源
。。。 。。。
}

通过onMeasure()来计算自定义view的大小:

[java]
view plaincopyprint?

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int minimumWidth = getSuggestedMinimumWidth();
final int minimumHeight = getSuggestedMinimumHeight();
int viewWidth = resolveMeasured(widthMeasureSpec, minimumWidth);
int viewHeight = resolveMeasured(heightMeasureSpec, minimumHeight);
setMeasuredDimension(viewWidth, viewHeight);
}

通过onLayout()来加载布局:

[java]
view plaincopyprint?

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
final int width = right - left;
final int height = bottom - top;
float newWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2;
float newWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2;
if (newWaveCenterX != mWaveCenterX || newWaveCenterY != mWaveCenterY) {
if (mWaveCenterX == 0 && mWaveCenterY == 0) {
performInitialLayout(newWaveCenterX, newWaveCenterY);
}
mWaveCenterX = newWaveCenterX;
mWaveCenterY = newWaveCenterY;

mOuterRing.setX(mWaveCenterX);
mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));

updateTargetPositions();
}
if (DEBUG) dump();
}

Step 5:来看看触摸屏幕时的事件处理onTouchEvent()代码如下:

[java]
view plaincopyprint?

@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getAction();

boolean handled = false;
switch (action) {
case MotionEvent.ACTION_DOWN:
handleDown(event);
handled = true;
break;

case MotionEvent.ACTION_MOVE:
handleMove(event);
handled = true;
break;

case MotionEvent.ACTION_UP:
handleMove(event);
handleUp(event);
handled = true;
break;

case MotionEvent.ACTION_CANCEL:
handleMove(event);
handled = true;
break;
}
invalidate();
return handled ? true : super.onTouchEvent(event);
}

通过handleMove()来处理移动事件:

[java]
view plaincopyprint?

private void handleMove(MotionEvent event) {
if (!mDragging) {
trySwitchToFirstTouchState(event);
return;
}

int activeTarget = -1;
final int historySize = event.getHistorySize();
for (int k = 0; k < historySize + 1; k++) {
float x = k < historySize ? event.getHistoricalX(k) : event.getX();
float y = k < historySize ? event.getHistoricalY(k) : event.getY();
float tx = x - mWaveCenterX;
float ty = y - mWaveCenterY;
float touchRadius = (float) Math.sqrt(dist2(tx, ty));
final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f;
float limitX = mWaveCenterX + tx * scale;
float limitY = mWaveCenterY + ty * scale;

boolean singleTarget = mTargetDrawables.size() == 1;
if (singleTarget) {
// Snap to outer ring if there's only one target
float snapRadius = mOuterRadius - mSnapMargin;
if (touchRadius > snapRadius) {
activeTarget = 0;
x = limitX;
y = limitY;
}
} else {
// If there's more than one target, snap to the closest one less than hitRadius away.
float best = Float.MAX_VALUE;
final float hitRadius2 = mHitRadius * mHitRadius;
for (int i = 0; i < mTargetDrawables.size(); i++) {
// Snap to the first target in range
TargetDrawable target = mTargetDrawables.get(i);
float dx = limitX - target.getX();
float dy = limitY - target.getY();
float dist2 = dx*dx + dy*dy;
if (target.isValid() && dist2 < hitRadius2 && dist2 < best) {
activeTarget = i;
best = dist2;
}
}
x = limitX;
y = limitY;
}
if (activeTarget != -1) {
switchToState(STATE_SNAP, x,y);
float newX = singleTarget ? limitX : mTargetDrawables.get(activeTarget).getX();
float newY = singleTarget ? limitY : mTargetDrawables.get(activeTarget).getY();
moveHandleTo(newX, newY, false);
TargetDrawable currentTarget = mTargetDrawables.get(activeTarget);
if (currentTarget.hasState(TargetDrawable.STATE_FOCUSED)) {
currentTarget.setState(TargetDrawable.STATE_FOCUSED);
mHandleDrawable.setAlpha(0.0f);
}
} else {
switchToState(STATE_TRACKING, x, y);
moveHandleTo(x, y, false);
mHandleDrawable.setAlpha(1.0f);
}
}

// Draw handle outside parent's bounds
invalidateGlobalRegion(mHandleDrawable);

if (mActiveTarget != activeTarget && activeTarget != -1) {
dispatchGrabbedEvent(activeTarget);
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
String targetContentDescription = getTargetDescription(activeTarget);
announceText(targetContentDescription);
}
}
mActiveTarget = activeTarget;
}

以上主要工作是绘制拖拽的参数以及绘制出来。通过invalidate()来主动刷屏幕;

在onDraw()方法中实现绘制图形,代码如下:

[java]
view plaincopyprint?

@Override
protected void onDraw(Canvas canvas) {
mOuterRing.draw(canvas);
for (TargetDrawable target : mTargetDrawables) {
if (target != null) {
target.draw(canvas);
}
}
for (TargetDrawable target : mChevronDrawables) {
if (target != null) {
target.draw(canvas);
}
}
mHandleDrawable.draw(canvas);
}

在handleMove()方法中——>trySwitchToFirstTouchState(event);——>switchToState()——>doFinish();

——>setGrabbedState() ————> mOnTriggerListener.onGrabbedStateChange(this, mGrabbedState);

设置回调。

Step 6: LockScreen.java中有个内部类,监听这个移动事件的状态,——> 代码如下:

[java]
view plaincopyprint?

class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
UnlockWidgetCommonMethods {

private final MultiWaveView mMultiWaveView;
private boolean mCameraDisabled;

MultiWaveViewMethods(MultiWaveView multiWaveView) {
mMultiWaveView = multiWaveView;
final boolean cameraDisabled = mLockPatternUtils.getDevicePolicyManager()
.getCameraDisabled(null);
if (cameraDisabled) {
Log.v(TAG, "Camera disabled by Device Policy");
mCameraDisabled = true;
} else {
// Camera is enabled if resource is initially defined for MultiWaveView
// in the lockscreen layout file
mCameraDisabled = mMultiWaveView.getTargetResourceId()
!= R.array.lockscreen_targets_with_camera;
}
}

public void updateResources() {
int resId;
if (mCameraDisabled) {
// Fall back to showing ring/silence if camera is disabled by DPM...
resId = mSilentMode ? R.array.lockscreen_targets_when_silent
: R.array.lockscreen_targets_when_soundon;
} else {
resId = R.array.lockscreen_targets_with_camera;
}
mMultiWaveView.setTargetResources(resId);
}

public void onGrabbed(View v, int handle) {

}

public void onReleased(View v, int handle) {

}

public void onTrigger(View v, int target) {
if (target == 0 || target == 1) { // 0 = unlock/portrait, 1 = unlock/landscape
mCallback.goToUnlockScreen();
} else if (target == 2 || target == 3) { // 2 = alt/portrait, 3 = alt/landscape
if (!mCameraDisabled) {
// Start the Camera
Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
mCallback.goToUnlockScreen();
} else {
toggleRingMode();
mUnlockWidgetMethods.updateResources();
mCallback.pokeWakelock();
}
}
}

public void onGrabbedStateChange(View v, int handle) {
// Don't poke the wake lock when returning to a state where the handle is
// not grabbed since that can happen when the system (instead of the user)
// cancels the grab.
if (handle != MultiWaveView.OnTriggerListener.NO_HANDLE) {
mCallback.pokeWakelock();
}
}

public View getView() {
return mMultiWaveView;
}

public void reset(boolean animate) {
mMultiWaveView.reset(animate);
}

public void ping() {
mMultiWaveView.ping();
}
}

重点看public void onTrigger()这个方法,用于处理拖拽启动那个activity,一个启动camera,一个正常解锁。

锁屏的大概这个流程就是这个样子了,大家应该会一目了然了。由于时间仓促,难免有点纰漏,希望大家指正错误,如有不解的地方,欢迎留言探讨!!!



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: