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

时间:2022-04-30 15:00:15

        先来说说LockScreen分类;

        一、无锁屏;

        二、锁屏:

                1、UnLockScreen:

                        图案锁、 PIN锁, 密码锁;

                2、LockScreen:

                        波纹锁;


           转载请表明出处:http://blog.csdn.net/wdaming1986/article/details/7753206

 

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

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


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

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

 

综上所述:

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

 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界面:

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类——>先看看构造函数:

 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步骤中根据横竖屏来加载横竖屏的布局:

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:来看看竖屏的布局文件的代码:

<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锁屏的拖拽的功能,具体代码如下:

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

 

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

 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()来加载布局:

 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()代码如下:

 @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()来处理移动事件:

 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()方法中实现绘制图形,代码如下:

    @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中有个内部类,监听这个移动事件的状态,——> 代码如下:

 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,一个正常解锁。

 

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