Android8.1 SystemUI Keyguard之滑動(dòng)解鎖流程

我們理解Keyguard的解鎖流程主要從鎖屏的界面Layout結(jié)構(gòu)缀拭、touchEvent事件分發(fā)、解鎖動(dòng)作邏輯幾個(gè)方面進(jìn)行源碼的分析

鎖屏的界面Layout結(jié)構(gòu)分析

StatusbarWindowView

整個(gè)鎖屏界面的頂級(jí)View就是mStatusBarWindow
src/com/android/systemui/statusbar/phone/StatusBar.java

    public void createAndAddWindows() {
        addStatusBarWindow();
    }

    private void addStatusBarWindow() {
        makeStatusBarView();
        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);
        mRemoteInputController = new RemoteInputController(mHeadsUpManager);
        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
        // add by hai.qin for story lock
        if (mLockScreenManager != null) {
            mLockScreenManager.setStatusBarWindowManager(mStatusBarWindowManager);
        }
        //
    }

src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java

    /**
     * Adds the status bar view to the window manager.
     *
     * @param statusBarView The view to add.
     * @param barHeight The height of the status bar in collapsed state.
     */
    public void add(View statusBarView, int barHeight) {

        // Now that the status bar window encompasses the sliding panel and its
        // translucent backdrop, the entire thing is made TRANSLUCENT and is
        // hardware-accelerated.
        mLp = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                barHeight,
                WindowManager.LayoutParams.TYPE_STATUS_BAR,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                PixelFormat.TRANSLUCENT);
        mLp.token = new Binder();
        mLp.gravity = Gravity.TOP;
        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
        mLp.setTitle("StatusBar");
        mLp.packageName = mContext.getPackageName();
        mStatusBarView = statusBarView;
        mBarHeight = barHeight;
        mWindowManager.addView(mStatusBarView, mLp);
        mLpChanged = new WindowManager.LayoutParams();
        mLpChanged.copyFrom(mLp);
    }

mStatusBarWindow是在StatusBar的create流程中調(diào)用WindowManager.addView()添加到窗口上的田巴, type為WindowManager.LayoutParams.TYPE_STATUS_BAR

Layout結(jié)構(gòu)

鎖屏界面的Layout結(jié)構(gòu)可以簡(jiǎn)單概括為以下結(jié)構(gòu):
mStatusBarWindow--> R.layout.super_status_bar
notification_panel--> R.layout.status_bar_expanded
keyguardBouncer-->R.layout.keyguard_bouncer

mStatusBarWindow-->notification_panel-->notification_container_parent-->keyguard_header(鎖屏狀態(tài)欄)
                |                    |
                |                    -->keyguard_bottom_area (lock_icon和充電狀態(tài)等)
                |                    |
                |                    -->keyguard_status_view (鎖屏?xí)r鐘日期)
                |                    |
                |                    -->keyguard_up_slide (箭頭提示動(dòng)畫)
                |
                -->keyguardBouncer(安全鎖界面)

上劃后顯示的安全鎖界面是KeyguardBouncer超歌,但keyguardbouncer并沒有寫在super_status_bar的layout文件里面专普,那么他是在什么時(shí)候添加的呢?

KeyguarBouncer何時(shí)創(chuàng)建

src/com/android/systemui/statusbar/phone/StatusBar.java
-->start()-->startKeyguard()

 protected void startKeyguard() {
 ...
        mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                getBouncerContainer(), mScrimController,
                mFingerprintUnlockController);
 ...
 }

src/com/android/systemui/keyguard/KeyguardViewMediator.java
-->registerStatusBar()
src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
-->registerStatusBar()

    public void registerStatusBar(StatusBar statusBar,
            ViewGroup container,
            ScrimController scrimController,
            FingerprintUnlockController fingerprintUnlockController,
            DismissCallbackRegistry dismissCallbackRegistry) {
        mStatusBar = statusBar;
        mContainer = container;
        mScrimController = scrimController;
        mFingerprintUnlockController = fingerprintUnlockController;
        mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
                mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
    }

那么這里的container是什么码耐?

    protected ViewGroup getBouncerContainer() {
        return mStatusBarWindow;
    }

是什么時(shí)候把keyguard_host_view加入到mStatuBarWindow的?

src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
-->show()-->ensureView()-->inflateView()

    protected void inflateView() {
        removeView();
        mHandler.removeCallbacks(mRemoveViewRunnable);
        mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
        mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
        mKeyguardView.setViewMediatorCallback(mCallback);
        mContainer.addView(mRoot, mContainer.getChildCount());
        mRoot.setVisibility(View.INVISIBLE);

        final WindowInsets rootInsets = mRoot.getRootWindowInsets();
        if (rootInsets != null) {
            mRoot.dispatchApplyWindowInsets(rootInsets);
        }
    }

不同類型的安全鎖是怎么放入keyguard_host_view的追迟?

src/com/android/keyguard/KeyguardSecurityContainer.java

    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
        KeyguardSecurityView view = null;
        final int children = mSecurityViewFlipper.getChildCount();
        for (int child = 0; child < children; child++) {
            if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
                view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
                break;
            }
        }
        int layoutId = getLayoutIdFor(securityMode);
        if (view == null && layoutId != 0) {
            final LayoutInflater inflater = LayoutInflater.from(mContext);
            if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
            View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);
            mSecurityViewFlipper.addView(v);
            updateSecurityView(v);
            view = (KeyguardSecurityView)v;
        }

        return view;
    }

每次獲取securityview的時(shí)候 先判斷是否在viewflippter里存在該id
沒有的話 inflate一個(gè)新的同時(shí)addview到viewflippter里面

在顯示的時(shí)候調(diào)用showSecurityScreen(SecurityMode securityMode)

    private void showSecurityScreen(SecurityMode securityMode) {
    ...

        // Find and show this child.
        final int childCount = mSecurityViewFlipper.getChildCount();

        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
        for (int i = 0; i < childCount; i++) {
            if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
                mSecurityViewFlipper.setDisplayedChild(i);
                break;
            }
        }
    ...
    }

會(huì)根據(jù)securitymode選擇viewflipper中對(duì)應(yīng)的child進(jìn)行顯示

touchEvent事件分發(fā)

我們這里分析上滑解鎖過程中的touchEvent事件分發(fā)
讓我們來先回顧一個(gè)android中的事件分發(fā)概念:事件序列

事件序列

在Android系統(tǒng)中,一個(gè)單獨(dú)的事件基本上是沒什么作用的骚腥,只有一個(gè)事件序列敦间,才有意義。一個(gè)事件序列正常情況下束铭,定義為 DOWN每瞒、MOVE(0或者多個(gè))、UP/CANCEL纯露。事件序列以DOWN事件開始,中間會(huì)有0或者多個(gè)MOVE事件代芜,最后以UP事件或者CANCEL事件結(jié)束埠褪。

DOWN事件作為序列的開始,有一個(gè)很重要的職責(zé)挤庇,就是尋找事件序列的接受者钞速,怎么理解呢?framework 在DOWN事件的傳遞過程中嫡秕,需要根據(jù)View事件處理方法(onTouchEvent)的返回值來確定事件序列的接受者渴语。如果一個(gè)View的onTouchEvent事件,在處理DOWN事件的時(shí)候返回true昆咽,說明它愿意接受并處理該事件序列驾凶。

上滑解鎖

當(dāng)用戶移動(dòng)手指時(shí),產(chǎn)生touch down事件掷酗,
最外層view StatusBarWindowView會(huì)執(zhí)行onInterceptTouchEvent调违,看是否需要攔截touch事件
再一級(jí)級(jí)往子View傳遞,都沒有被攔截泻轰,之后執(zhí)行OnTouchEvent從子View開始一級(jí)級(jí)往父View傳遞技肩,到PanelView這里當(dāng)手指移動(dòng)的距離達(dá)到一定的閾值會(huì)調(diào)用onTrackingStarted從而設(shè)置mTracking的值為true,onTouchEvent返回true浮声,接收此touch move事件虚婿,之后的touch事件直接傳到此View。
在用戶滑動(dòng)過程會(huì)調(diào)用setExpandedHeightInternal,進(jìn)而調(diào)用NotificationPanelView的onHeightUpdated進(jìn)行鎖屏上的時(shí)間和通知View根據(jù)手指的移動(dòng)距離進(jìn)行縮小泳挥、變透明處理然痊。
當(dāng)用戶抬起手指時(shí),產(chǎn)生touch up事件羡洁,PanelView接收到這個(gè)事件后會(huì)調(diào)用endMotionEvent玷过,如果手指從down到up之間移動(dòng)的距離達(dá)到一定閾值會(huì)調(diào)用onTrackingStopped

在上滑過程中,不斷調(diào)用PanelView.java的setExpandedHeightInternal()->notifyBarPanelExpansionChanged()-->PanelBar.java的notifyBarPanelExpansionChanged()
src/com/android/systemui/statusbar/phone/PanelBar.java

    public void panelExpansionChanged(float frac, boolean expanded) {
        Log.d("WANG", "panelExpansionChanged frac=" + frac + " expaned=" + expanded );
        boolean fullyClosed = true;
        boolean fullyOpened = false;
        if (SPEW) LOG("panelExpansionChanged: start state=%d", mState);
        PanelView pv = mPanel;
        pv.setVisibility(expanded ? VISIBLE : INVISIBLE);
        // adjust any other panels that may be partially visible
        if (expanded) {
            if (mState == STATE_CLOSED) {
                go(STATE_OPENING);
                onPanelPeeked();
            }
            fullyClosed = false;
            final float thisFrac = pv.getExpandedFraction();
            if (SPEW) LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
            fullyOpened = thisFrac >= 1f;
        }
        if (fullyOpened && !mTracking) {
            go(STATE_OPEN);
            onPanelFullyOpened();
        } else if (fullyClosed && !mTracking && mState != STATE_CLOSED) {
            go(STATE_CLOSED);
            onPanelCollapsed();
        }

        if (SPEW) LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
                fullyOpened?" fullyOpened":"", fullyClosed?" fullyClosed":"");
    }

達(dá)到閾值時(shí),expanded == false fullyClosed == true
調(diào)用onPanelCollapsed()->調(diào)用子類PhoneStatubarView.java的onPanelCollapsed()
src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java

 @Override
    public void onPanelCollapsed() {
        super.onPanelCollapsed();
        // Close the status bar in the next frame so we can show the end of the animation.
        post(mHideExpandedRunnable);
        mIsFullyOpenedPanel = false;
    }
    private Runnable mHideExpandedRunnable = new Runnable() {
        @Override
        public void run() {
            if (mPanelFraction == 0.0f) {
                mBar.makeExpandedInvisible();
            }
        }
    };

解鎖動(dòng)作邏輯

整個(gè)解鎖過程分為兩個(gè)部分:1. 隱藏notification_panel 2. 展示keyguard_bouncer或直接解鎖

src/com/android/systemui/statusbar/phone/StatusBar.java

    void makeExpandedInvisible() {
        if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
                + " mExpandedVisible=" + mExpandedVisible);

        if (!mExpandedVisible || mStatusBarWindow == null) {
            return;
        }

        // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
        mStatusBarView.collapsePanel(/*animate=*/ false, false /* delayed*/,
                1.0f /* speedUpFactor */);

        mNotificationPanel.closeQs();

        mExpandedVisible = false;
        visibilityChanged(false);

        // Shrink the window to the size of the status bar only
        mStatusBarWindowManager.setPanelVisible(false);
        mStatusBarWindowManager.setForceStatusBarVisible(false);

        // Close any guts that might be visible
        closeAndSaveGuts(true /* removeLeavebehind */, true /* force */, true /* removeControls */,
                -1 /* x */, -1 /* y */, true /* resetMenu */);

        runPostCollapseRunnables();
        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
        showBouncerIfKeyguard();
        recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);

        // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
        // the bouncer appear animation.
        if (!mStatusBarKeyguardViewManager.isShowing()) {
            WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
        }
    }

mStatusBarWindowManager.setPanelVisible(false);
調(diào)用WindowManager更改為StatusBarWindow的高度辛蚊, 只保留狀態(tài)欄高度
mStatusBarWindowManager.setForceStatusBarVisible(false);
調(diào)用WindowManager使?fàn)顟B(tài)欄不可見
showBouncerIfKeyguard()->showBouncer()最終調(diào)用到StatusBarKeyguardViewManager的dismiss()->showBouncer()方法

src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java

    private void showBouncer() {
        if (mShowing) {
            mBouncer.show(false /* resetSecuritySelection */);
        }
        updateStates();
    }

src/com/android/systemui/statusbar/phone/KeyguardBouncer.java

    public void show(boolean resetSecuritySelection) {
        ...
        // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
        // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
        if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
            return;
        }
        ...
    }

在沒有安全鎖的情況下粤蝎,會(huì)回調(diào)KeyguardHostView的finish方法

    @Override
    public void finish(boolean strongAuth, int targetUserId) {
        // If there's a pending runnable because the user interacted with a widget
        // and we're leaving keyguard, then run it.
        boolean deferKeyguardDone = false;
        if (mDismissAction != null) {
            deferKeyguardDone = mDismissAction.onDismiss();
            mDismissAction = null;
            mCancelAction = null;
        }
        if (mViewMediatorCallback != null) {
            if (deferKeyguardDone) {
                mViewMediatorCallback.keyguardDonePending(strongAuth, targetUserId);
            } else {
                mViewMediatorCallback.keyguardDone(strongAuth, targetUserId);
            }
        }
    }

mViewMediatorCallback定義在KeyguardViewMediator中

  @Override
        public void keyguardDone(boolean strongAuth, int targetUserId) {
            if (targetUserId != ActivityManager.getCurrentUser()) {
                return;
            }

            tryKeyguardDone();
        }

一系列調(diào)用來到解鎖的核心代碼
mKeyguardGoingAwayRunnable.run();

    private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
        @Override
        public void run() {
            Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
            if (DEBUG) Log.d(TAG, "keyguardGoingAway");
            //Modified for MYOS begin

            try {
                mStatusBarKeyguardViewManager.keyguardGoingAway();

                int flags = 0;
                if (mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()
                        || mWakeAndUnlocking || mAniSpeedup) {
                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
                }
                if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()) {
                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
                }
                if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) {
                    flags |= WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
                }

                mUpdateMonitor.setKeyguardGoingAway(true /* goingAway */);
                // Don't actually hide the Keyguard at the moment, wait for window
                // manager until it tells us it's safe to do so with
                // startKeyguardExitAnimation.
                ActivityManager.getService().keyguardGoingAway(flags);
            } catch (RemoteException e) {
                Log.e(TAG, "Error while calling WindowManager", e);
            }

            //Modified for MYOS end
            Trace.endSection();
        }
    };

解鎖過程的核心實(shí)質(zhì)上是鎖屏啟動(dòng)了一個(gè)runnable,
通知AMS和WMS顯示鎖屏下方的activity組件窗口以及調(diào)用該activity組件的生命周期

    void keyguardGoingAway(int flags) {
        if (!mKeyguardShowing) {
            return;
        }
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway");
        mWindowManager.deferSurfaceLayout();
        try {
            setKeyguardGoingAway(true);
            mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
                    false /* alwaysKeepCurrent */, convertTransitFlags(flags),
                    false /* forceOverride */);
            updateKeyguardSleepToken();

            // Some stack visibility might change (e.g. docked stack)
            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            mStackSupervisor.addStartingWindowsForVisibleActivities(true /* taskSwitch */);
            mWindowManager.executeAppTransition();
        } finally {
            Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "keyguardGoingAway: surfaceLayout");
            mWindowManager.continueSurfaceLayout();
            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

在系統(tǒng)準(zhǔn)備解鎖完成后袋马,PhoneWindowManager回調(diào)KeyguardService的startKeyguardExitAnimation

  private void handleStartKeyguardExitAnimation(long startTime, long fadeoutDuration) {
      Trace.beginSection("KeyguardViewMediator#handleStartKeyguardExitAnimation");
      if (DEBUG) Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
              + " fadeoutDuration=" + fadeoutDuration);
      synchronized (KeyguardViewMediator.this) {

          if (!mHiding) {
              return;
          }
          mHiding = false;

          if (mWakeAndUnlocking && mDrawnCallback != null) {

              // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
              // the next draw from here so we don't have to wait for window manager to signal
              // this to our ViewRootImpl.
              mStatusBarKeyguardViewManager.getViewRootImpl().setReportNextDraw();
              notifyDrawn(mDrawnCallback);
              mDrawnCallback = null;
          }

          // only play "unlock" noises if not on a call (since the incall UI
          // disables the keyguard)
          if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
              playSounds(false);
          }

          mWakeAndUnlocking = false;
          setShowingLocked(false);
          mDismissCallbackRegistry.notifyDismissSucceeded();
          mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
          resetKeyguardDonePendingLocked();
          mHideAnimationRun = false;
          adjustStatusBarLocked();
          sendUserPresentBroadcast();
          mUpdateMonitor.setKeyguardGoingAway(false /* goingAway */);

          // ADD FOR FINGERPRINT SHOT BEGIN
          mFingerPrintManager.notifyFpService(1, null);
          // ADD FOR FINGERPRINT SHOT END
      }
      Trace.endSection();
  }

播放解鎖聲音初澎、設(shè)置StatusBar的flag、發(fā)出ACTION_USER_PRESENT廣播虑凛、隱藏KeyguardView碑宴,解鎖流程結(jié)束

推薦文章

Android View的事件分發(fā)機(jī)制探索

解鎖的framework流程及動(dòng)畫

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市桑谍,隨后出現(xiàn)的幾起案子延柠,更是在濱河造成了極大的恐慌,老刑警劉巖锣披,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贞间,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雹仿,警方通過查閱死者的電腦和手機(jī)增热,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胧辽,“玉大人峻仇,你說我怎么就攤上這事∫厣蹋” “怎么了摄咆?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奠骄。 經(jīng)常有香客問我豆同,道長(zhǎng),這世上最難降的妖魔是什么含鳞? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任影锈,我火速辦了婚禮,結(jié)果婚禮上蝉绷,老公的妹妹穿的比我還像新娘鸭廷。我一直安慰自己,他們只是感情好熔吗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布辆床。 她就那樣靜靜地躺著,像睡著了一般桅狠。 火紅的嫁衣襯著肌膚如雪讼载。 梳的紋絲不亂的頭發(fā)上轿秧,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音咨堤,去河邊找鬼菇篡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛一喘,可吹牛的內(nèi)容都是我干的驱还。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼凸克,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼议蟆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起萎战,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤咐容,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蚂维,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疟丙,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年鸟雏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片览祖。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡孝鹊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出展蒂,到底是詐尸還是另有隱情又活,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布锰悼,位于F島的核電站柳骄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏箕般。R本人自食惡果不足惜耐薯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望丝里。 院中可真熱鬧曲初,春花似錦、人聲如沸杯聚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幌绍。三九已至颁褂,卻和暖如春故响,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颁独。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工彩届, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人奖唯。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓惨缆,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親丰捷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坯墨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,846評(píng)論 25 707
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料病往? 從這篇文章中你...
    hw1212閱讀 12,704評(píng)論 2 59
  • Android 6.0 SystemUI 鎖屏流程解析 談到鎖屏我們先來簡(jiǎn)單看下systemUI的啟動(dòng)流程 Sys...
    開荒的人閱讀 5,068評(píng)論 0 7
  • 總是期待一周的小美好在周四晚上分分鐘刷完捣染,也終于大結(jié)局了⊥O铮看完之后怎么說呢耍攘,在預(yù)料之中,但還是有遺憾畔勤。 ...
    小肉球_5248閱讀 301評(píng)論 0 0
  • 最后的視頻和效果 Video:https://vimeo.com/272578288 Introduction I...
    小本兒_生意閱讀 1,016評(píng)論 0 2