Android 10.0 截屏流程

通常未通過特殊定制的 Android 系統(tǒng)叔遂,截屏都是經(jīng)過同時按住音量下鍵和電源鍵來截屏憋飞。本篇文章就只討論使用這些特殊按鍵來進行截屏霎苗。

這里我們就要明白事件是在哪里進行分發(fā)攔截的。通過源碼的分析榛做,我們發(fā)現(xiàn)是在PhoneWindowManager.java 中唁盏。
PhoneWindowManager#interceptKeyBeforeQueueing()

// frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
    @Override
    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
        if (!mSystemBooted) {
            // If we have not yet booted, don't let key events do anything.
            return 0;
        }

        // 省略部分代碼......

        // Handle special keys.
        switch (keyCode) {

             ......

            case KeyEvent.KEYCODE_VOLUME_DOWN:
            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_VOLUME_MUTE: {
                // 按下音量鍵調(diào)用
                handleVolumeKey(event, policyFlags);

                ......

                break;
            }

            ......

            case KeyEvent.KEYCODE_POWER: {
                ......
                if (down) {

                    // 按下電源鍵將調(diào)用
                    interceptPowerKeyDown(event, interactive);

                } else {          
                    interceptPowerKeyUp(event, interactive, canceled);
                }
                break;
            }
        }
        return result;
    }
1、電源鍵處理

PhoneWindowManager#interceptPowerKeyDown()

// PhoneWindowManager.java
    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {

        // 省略部分代碼......

        // Latch power key state to detect screenshot chord.
        if (interactive && !mScreenshotChordPowerKeyTriggered
                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {

            // power鍵按下的標志
            mScreenshotChordPowerKeyTriggered = true;

            // 獲取 Power 鍵的觸發(fā)時間
            mScreenshotChordPowerKeyTime = event.getDownTime();

            // 處理屏幕截圖事件
            interceptScreenshotChord();
            // 這個方法應該是消耗检眯、攔截事件的厘擂,避免改變音量、鈴聲等锰瘸。
            interceptRingerToggleChord();
        }

        // 省略部分代碼......

    }

interceptScreenshotChord()該方法下面再說刽严,先介紹電源按鍵、音量按鍵的處理避凝。

2舞萄、音量鍵處理

PhoneWindowManager#handleVolumeKey()

// PhoneWindowManager.java
    public void handleVolumeKey(KeyEvent event, int policyFlags) {
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
        final int keyCode = event.getKeyCode();
        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            if (down) {
                // Any activity on the vol down button stops the ringer toggle shortcut
                cancelPendingRingerToggleChordAction();

                if (interactive && !mScreenshotChordVolumeDownKeyTriggered
                        && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {

                    // Volume鍵按下的標志
                    mScreenshotChordVolumeDownKeyTriggered = true;

                    // 獲取 Volume 鍵的觸發(fā)時間
                    mScreenshotChordVolumeDownKeyTime = event.getDownTime();

                    // 賦值  false 該屬性為了防止截屏的時候音量下鍵生效出現(xiàn)調(diào)節(jié)音量的 dialog 狀態(tài)值
                    mScreenshotChordVolumeDownKeyConsumed = false;

                    // 防止觸發(fā) Power  鍵長按功能
                    cancelPendingPowerKeyAction();

                    //處理屏幕截圖事件
                    interceptScreenshotChord();
                    // 攔截相關快捷鍵
                    interceptAccessibilityShortcutChord();
                }
            } else {
                 // 省略部分代碼......
            }
        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {

             // 省略部分代碼......

        }
        return;
    }
3眨补、截屏事件處理 interceptScreenshotChord()

PhoneWindowManager#interceptScreenshotChord()

// PhoneWindowManager.java
    private void interceptScreenshotChord() {
          /*
           * if 判斷參數(shù)介紹
           * mScreenshotChordEnabled 其值為mContext.getResources().getBoolean(com.android.internal.R.bool.config_enableScreenshotChord);
           * mScreenshotChordVolumeDownKeyTriggered 音量下鍵按下時值為true
           * mScreenshotChordPowerKeyTriggered  電源鍵按下時值為true
           * mA11yShortcutChordVolumeUpKeyTriggered 音量上(加)鍵抬起時為false , 按下時為true
           **/
        if (mScreenshotChordEnabled
                && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
                && !mA11yShortcutChordVolumeUpKeyTriggered) {
            // 獲取當前時間
            final long now = SystemClock.uptimeMillis();
            // 當前時間小于 音量下鍵按下時間 + 150ms
            // 當前時間小于 power鍵按下時間 + 150ms
            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
                    && now <= mScreenshotChordPowerKeyTime
                    + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {

                boolean inLongScreenshot = Settings.System.getIntForUser(mContext.getContentResolver(),
                        LONGSCREENSHOT_SETTING, 0, UserHandle.USER_CURRENT_OR_SELF) == 1;

                if (hasInPowerUtrlSavingMode() || inLongScreenshot) {
                    return;
                }
      
                // 長按音量下鍵,達到截屏條件倒脓,將該事件消費掉撑螺。
                mScreenshotChordVolumeDownKeyConsumed = true;

                // 防止觸發(fā) Power  鍵長按功能
                cancelPendingPowerKeyAction();

                // 設置截圖的類型,TAKE_SCREENSHOT_FULLSCREEN 為全屏
                mScreenshotRunnable.setScreenshotType(TAKE_SCREENSHOT_FULLSCREEN);

                // 截圖的方式崎弃,(例如:按鍵甘晤、三指下滑 等等)
                mScreenshotRunnable.setScreenshotSource(SCREENSHOT_KEY_CHORD);

                //執(zhí)行 mScreenshotRunnable
                mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
            }
        }
    }

繼續(xù)查看ScreenshotRunnable,此時會一步步向下調(diào)用饲做,最終到SystemUI线婚。

// PhoneWindowManager.java
    private class ScreenshotRunnable implements Runnable {
        private int mScreenshotType = TAKE_SCREENSHOT_FULLSCREEN;
        private int mScreenshotSource = SCREENSHOT_KEY_OTHER;

        public void setScreenshotType(int screenshotType) {
            mScreenshotType = screenshotType;
        }

        public void setScreenshotSource(int screenshotSource) {
            mScreenshotSource = screenshotSource;
        }

        @Override
        public void run() {
            // 回調(diào)到 DisplayPolicy.java
            mDefaultDisplayPolicy.takeScreenshot(mScreenshotType, mScreenshotSource);
        }
    }

DisplayPolicy#takeScreenshot()

// DisplayPolicy.java

    // 請求截取屏幕截圖
    public void takeScreenshot(int screenshotType, int source) {
        if (mScreenshotHelper != null) {
            mScreenshotHelper.takeScreenshot(screenshotType,
                    mStatusBar != null && mStatusBar.isVisibleLw(),
                    mNavigationBar != null && mNavigationBar.isVisibleLw(),
                    source, mHandler, null /* completionConsumer */);
        }
    }

繼續(xù)往下看ScreenshotHelper#takeScreenshot()

// ScreenshotHelper.java

    // 請求截取屏幕截圖
    public void takeScreenshot(final int screenshotType, final boolean hasStatus,
            final boolean hasNav, int source, @NonNull Handler handler,
            @Nullable Consumer<Uri> completionConsumer) {
        ScreenshotRequest screenshotRequest = new ScreenshotRequest(source, hasStatus, hasNav);
        takeScreenshot(screenshotType, SCREENSHOT_TIMEOUT_MS, handler, screenshotRequest,
                completionConsumer);
    }


    //到了 Binder調(diào)用環(huán)節(jié), 此為客戶端, 服務端為SystemUI中的 TakeScreenshotService
    private void takeScreenshot(final int screenshotType, long timeoutMs, @NonNull Handler handler,
                ScreenshotRequest screenshotRequest, @Nullable Consumer<Uri> completionConsumer) {
            synchronized (mScreenshotLock) {

                final Runnable mScreenshotTimeout = () -> {
                    synchronized (mScreenshotLock) {
                        if (mScreenshotConnection != null) {
                            // 在獲取屏幕截圖捕獲響應之前超時
                            Log.e(TAG, "Timed out before getting screenshot capture response");
                            // 重置連接
                            resetConnection();
                            // 通知截屏錯誤
                            notifyScreenshotError();
                        }
                    }
                    if (completionConsumer != null) {
                        completionConsumer.accept(null);
                    }

                };


                Message msg = Message.obtain(null, screenshotType, screenshotRequest);
                Handler h = new Handler(handler.getLooper()) {
                    @Override
                    public void handleMessage(Message msg) {
                        switch (msg.what) {
                            case SCREENSHOT_MSG_URI:
                                if (completionConsumer != null) {
                                    completionConsumer.accept((Uri) msg.obj);
                                }
                                handler.removeCallbacks(mScreenshotTimeout);
                                break;
                            case SCREENSHOT_MSG_PROCESS_COMPLETE:
                                synchronized (mScreenshotLock) {
                                    resetConnection();
                                }
                                break;
                        }
                    }
                };
                msg.replyTo = new Messenger(h);
                if (mScreenshotConnection == null || mScreenshotService == null) {
                    // 一個標準的Service連接
                    // config_screenshotServiceComponent == com.android.systemui/com.android.systemui.screenshot.TakeScreenshotService
                    final ComponentName serviceComponent = ComponentName.unflattenFromString(
                            mContext.getResources().getString(
                                    com.android.internal.R.string.config_screenshotServiceComponent));
                    final Intent serviceIntent = new Intent();
                    serviceIntent.setComponent(serviceComponent);
                    ServiceConnection conn = new ServiceConnection() {
                        @Override
                        // 當Service連接成功之后
                        public void onServiceConnected(ComponentName name, IBinder service) {
                            synchronized (mScreenshotLock) {
                                if (mScreenshotConnection != this) {
                                    return;
                                }
                                mScreenshotService = service;
                                Messenger messenger = new Messenger(mScreenshotService);
                                try {
                                    messenger.send(msg);
                                } catch (RemoteException e) {
                                    Log.e(TAG, "Couldn't take screenshot: " + e);
                                    if (completionConsumer != null) {
                                        completionConsumer.accept(null);
                                    }
                                }
                            }
                        }
                        @Override
                        // 當Service斷開連接時
                        public void onServiceDisconnected(ComponentName name) {
                            synchronized (mScreenshotLock) {
                                if (mScreenshotConnection != null) {
                                    resetConnection();
                                    // only log an error if we're still within the timeout period
                                    if (handler.hasCallbacks(mScreenshotTimeout)) {
                                        handler.removeCallbacks(mScreenshotTimeout);
                                        notifyScreenshotError();
                                    }
                                }
                            }
                        }
                    };
                    // bindService
                    if (mContext.bindServiceAsUser(serviceIntent, conn,
                            Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                            UserHandle.CURRENT)) {
                        mScreenshotConnection = conn;
                        handler.postDelayed(mScreenshotTimeout, timeoutMs);
                    }
                } else {
                    // 如果已經(jīng)連接則直接發(fā)送Message
                    Messenger messenger = new Messenger(mScreenshotService);
                    try {
                        messenger.send(msg);
                    } catch (RemoteException e) {
                        Log.e(TAG, "Couldn't take screenshot: " + e);
                        if (completionConsumer != null) {
                            completionConsumer.accept(null);
                        }
                    }
                    handler.postDelayed(mScreenshotTimeout, timeoutMs);
                }
            }
    }

客戶端通過向服務端發(fā)送 message 來將截屏任務交給 service,由 service 處理后面的操作盆均。

// TakeScreenshotService.java
    private Handler mHandler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            // 獲取客戶端傳的 Messenger 對象
            final Messenger callback = msg.replyTo;
            Consumer<Uri> uriConsumer = uri -> {
                Message reply = Message.obtain(null, SCREENSHOT_MSG_URI, uri);
                try {
                    / /Messenger 雙向通信塞弊,在服務端用遠程客戶端的 Messenger 對象給客戶端發(fā)送信息
                    callback.send(reply);
                } catch (RemoteException e) {
                }
            };
            Runnable onComplete = () -> {
                Message reply = Message.obtain(null, SCREENSHOT_MSG_PROCESS_COMPLETE);
                try {
                    callback.send(reply);
                } catch (RemoteException e) {
                }
            };
    
            // 判斷用戶的設備是否為解鎖狀態(tài)
            // 如果用戶的存儲被鎖定,我們沒有地方存儲截圖缀踪,所以跳過它,而不是顯示一個誤導性的動畫和錯誤通知虹脯。
            if (!mUserManager.isUserUnlocked()) {
                Log.w(TAG, "Skipping screenshot because storage is locked!");
                post(() -> uriConsumer.accept(null));
                post(onComplete);
                return;
            }
            ScreenshotHelper.ScreenshotRequest screenshotRequest =
                    (ScreenshotHelper.ScreenshotRequest) msg.obj;
            mUiEventLogger.log(ScreenshotEvent.getScreenshotSource(screenshotRequest.getSource()));
            switch (msg.what) {
                case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:  // 全屏截圖
                    // 我們在PhoneWindowManager傳入的type為全屏截圖,所以需要執(zhí)行全屏截圖流程
                    mScreenshot.takeScreenshot(uriConsumer, onComplete);
                    break;
                case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:  // 區(qū)域截圖
                    mScreenshot.takeScreenshot(uriConsumer, onComplete);
                    break;
                case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
                    Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
                            screenshotRequest.getBitmapBundle());
                    Rect screenBounds = screenshotRequest.getBoundsInScreen();
                    Insets insets = screenshotRequest.getInsets();
                    int taskId = screenshotRequest.getTaskId();
                    int userId = screenshotRequest.getUserId();
                    ComponentName topComponent = screenshotRequest.getTopComponent();
                    mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
                            taskId, userId, topComponent, uriConsumer, onComplete);
                    break;
                default:
                    Log.d(TAG, "Invalid screenshot option: " + msg.what);
            }
        }
    };

TakeScreenshotService調(diào)用GlobalScreenshot.java的takeScreenshot()驴娃;
GlobalScreenshot#takeScreenshot()

// GlobalScreenshot.java

    /**
     *截取當前顯示的屏幕截圖并顯示動畫。.
     */
    private void takeScreenshot(Consumer<Uri> finisher, Rect crop) {
        // copy the input Rect, since SurfaceControl.screenshot can mutate it
        Rect screenRect = new Rect(crop);
        int rot = mDisplay.getRotation();
        int width = crop.width();
        int height = crop.height();
        takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect,
                Insets.NONE, true);
    }


    private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
            Insets screenInsets, boolean showFlash) {
        // 此方法會清除上一次的截圖信息--連續(xù)截圖行為
        dismissScreenshot("new screenshot requested", true);

        mScreenBitmap = screenshot;

        if (mScreenBitmap == null) {
            // 如果沒有Bitmap則報告錯誤信息
            mNotificationsController.notifyScreenshotError(
                    R.string.screenshot_failed_to_capture_text);
            finisher.accept(null);
            mOnCompleteRunnable.run();
            return;
        }

        if (!isUserSetupComplete()) {
            // 用戶設置尚未完成,不應該向用戶展示 分享和編輯 , 只顯示一個Toast并保存圖片
            saveScreenshotAndToast(finisher);
            return;
        }

        // Optimizations
        mScreenBitmap.setHasAlpha(false);
        mScreenBitmap.prepareToDraw();

        onConfigChanged(mContext.getResources().getConfiguration());

        if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
            mDismissAnimation.cancel();
        }

        // 獲取焦點
        setWindowFocusable(true);

        // 開始截圖后動畫
        startAnimation(finisher, screenRect, screenInsets, showFlash);
    }



    /**
     * 截屏后開始動畫
     */
    private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets,
            boolean showFlash) {
        if (mScreenshotIng == false) {//unisoc: Modify for bug1360276
            mScreenshotIng = true;

     
            // 如果開啟了省電模式循集,顯示 toast唇敞,以便有一些視覺提示已截取屏幕截圖
            PowerManager powerManager =(PowerManager) mContext . getSystemService (Context.POWER_SERVICE);
            if (powerManager.isPowerSaveMode()) {
                Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show();
            }

            mScreenshotHandler.post(() -> {
                if (!mScreenshotLayout.isAttachedToWindow()) {
                    // mScreenshotLayout是截屏的縮略圖的父View
                    // mScreenshotLayout 在 GlobalScreenshot.java 的構(gòu)造方法中初始化。對應布局文件:global_screenshot.xml
                    mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
                }
                // 動畫相關的View
                mScreenshotAnimatedView.setImageDrawable(
                        createScreenDrawable(mScreenBitmap, screenInsets));
                setAnimatedViewSize(screenRect.width(), screenRect.height());

                // 顯示動畫何時開始
                mScreenshotAnimatedView.setVisibility(View.GONE);

                //縮略圖顯示的View,將native層返回的Bitmap加載到此View上
                mScreenshotPreview.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets));

                // 使靜態(tài)預覽不可見(消失)咒彤,以便我們可以在屏幕上查詢其位置
                mScreenshotPreview.setVisibility(View.INVISIBLE);

                mScreenshotHandler.post(() -> {
                mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);

                // 創(chuàng)建動畫
                mScreenshotAnimation =
                        createScreenshotDropInAnimation(screenRect, showFlash);

                // 保存截圖
                saveScreenshotInWorkerThread(finisher, new ActionsReadyListener () {
                    @Override
                    void onActionsReady (SavedImageData imageData) {
                        showUiOnActionsReady(imageData);
                        mScreenshotIng = false;
                    }
                });

                // 播放快門聲音以通知我們已截屏
                mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
                if (mScreenshotPreview.isAttachedToWindow()) {
                    mScreenshotPreview.setLayerType(View.LAYER_TYPE_HARDWARE, null);
                    mScreenshotPreview.buildLayer();
                }
                // 開始執(zhí)行動畫
                mScreenshotAnimation.start();
            });
            });

        }

    }



    /**
     * 創(chuàng)建一個新的工作線程并將屏幕截圖保存到媒體存儲
     */
    private void saveScreenshotInWorkerThread(
            Consumer<Uri> finisher, @Nullable ActionsReadyListener actionsReadyListener) {
        SaveImageInBackgroundData data = new SaveImageInBackgroundData();
        data.image = mScreenBitmap;  // native 層返回的 Bitmap
        data.finisher = finisher;
        data.mActionsReadyListener = actionsReadyListener;

        if (mSaveInBgTask != null) {
            // just log success/failure for the pre-existing screenshot
            // 只需記錄預先存在的屏幕截圖的成功失敗
            mSaveInBgTask.setActionsReadyListener(new ActionsReadyListener() {
                @Override
                void onActionsReady(SavedImageData imageData) {
                    logSuccessOnActionsReady(imageData);
                }
            });
        }
        // 截圖的一些信息存儲在 SaveImageInBackgroundTask 中構(gòu)建
        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data);
        mSaveInBgTask.execute();
    }

到此截屏流程完畢,可以查看下截圖的View的xml文件:global_screenshot.xml


<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/global_screenshot_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/global_screenshot_actions_background"
        android:layout_height="@dimen/screenshot_bg_protection_height"
        android:layout_width="match_parent"
        android:layout_gravity="bottom"
        android:alpha="0.0"
        android:src="@drawable/screenshot_actions_background_protection"/>
    <!--截屏動畫相關的View -->
    <ImageView
        android:id="@+id/global_screenshot_animated_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|start"
        android:visibility="gone"
        android:elevation="@dimen/screenshot_preview_elevation"
        android:background="@drawable/screenshot_rounded_corners" />
    <ImageView
        android:id="@+id/global_screenshot_flash"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"
        android:elevation="@dimen/screenshot_preview_elevation"
        android:src="@android:color/white"/>
    <com.android.systemui.screenshot.ScreenshotSelectorView
        android:id="@+id/global_screenshot_selector"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"
        android:pointerIcon="crosshair"/>
    <!-- 此處包含了一個layout, 而縮略圖的View就在此layout中疆柔,
         截屏右上角的關閉縮略圖按鈕 也在此layout中 -->
    <include layout="@layout/global_screenshot_static"/>

</FrameLayout>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市镶柱,隨后出現(xiàn)的幾起案子旷档,更是在濱河造成了極大的恐慌,老刑警劉巖歇拆,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鞋屈,死亡現(xiàn)場離奇詭異,居然都是意外死亡故觅,警方通過查閱死者的電腦和手機厂庇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來输吏,“玉大人权旷,你說我怎么就攤上這事」峤Γ” “怎么了拄氯?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵躲查,是天一觀的道長。 經(jīng)常有香客問我坤邪,道長熙含,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任艇纺,我火速辦了婚禮怎静,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘黔衡。我一直安慰自己蚓聘,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布盟劫。 她就那樣靜靜地躺著夜牡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侣签。 梳的紋絲不亂的頭發(fā)上塘装,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音影所,去河邊找鬼蹦肴。 笑死,一個胖子當著我的面吹牛猴娩,可吹牛的內(nèi)容都是我干的阴幌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼卷中,長吁一口氣:“原來是場噩夢啊……” “哼矛双!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蟆豫,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤议忽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后十减,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體徙瓶,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年嫉称,在試婚紗的時候發(fā)現(xiàn)自己被綠了侦镇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡织阅,死狀恐怖壳繁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤闹炉,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布蒿赢,位于F島的核電站,受9級特大地震影響渣触,放射性物質(zhì)發(fā)生泄漏羡棵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一嗅钻、第九天 我趴在偏房一處隱蔽的房頂上張望皂冰。 院中可真熱鬧,春花似錦养篓、人聲如沸秃流。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舶胀。三九已至,卻和暖如春碧注,著一層夾襖步出監(jiān)牢的瞬間嚣伐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工萍丐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留轩端,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓碉纺,卻偏偏與公主長得像船万,于是被迫代替她去往敵國和親刻撒。 傳聞我的和親對象是個殘疾皇子骨田,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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